import { useEffect, useState } from 'react';
import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';
import { open } from '@tauri-apps/plugin-dialog';
import { load } from '@tauri-apps/plugin-store';

import "./App.css";

const FILE_STORAGE = 'launcher-settings.json';
const GAME_DIR_KEY = 'game-directory';

// enum with install status
enum InstallStatus {
    NotInstalled = 'NotInstalled',
    CheckingServer = 'CheckingServer',
    Downloading = 'Downloading',
    Unpacking = 'Unpacking',
    Installed = 'Installed',
}

interface Game {
    id: string;
    name: string;
    description: string;
    size: number;
    thumbnail: Uint8Array;
    installed: boolean;
    install_status: InstallStatus;
}

const App = () => {
    const [gameItems, setGameItems] = useState<Game[]>([]);
    const [searchTerm, setSearchTerm] = useState('');
    const [gameDir, setGameDir] = useState('');

    const filteredGames = gameItems.filter(item =>
        item.name.toLowerCase().includes(searchTerm.toLowerCase())
    );

    const getInitialGameDir = async () => {
        // update game directory from storage (if exists)
        // only if it's not already set
        await new Promise(resolve => setTimeout(resolve, 1000));
        const store = await load(FILE_STORAGE, { autoSave: true });
        const savedGameDir = await store.get<string>(GAME_DIR_KEY);
        if (savedGameDir) {
            setGameDir(savedGameDir);
        }
    };

    useEffect(() => {
        // Listen for game-unpack-finished events specifically
        const setupUnpackListener = async () => {
            const unlisten = await listen('game-unpack-finished', (event) => {
                const game_id = event.payload as string;
                console.log(`🗲 game-unpack-finished ${game_id} event received`);
                console.log('Current gameDir in listener:', gameDir); // Add this log
                setGameItems(prev => prev.map(item => item.id === game_id
                    ? {...item, install_status: InstallStatus.Installed}
                    : item));

                // Convert to string explicitly and verify it's not empty
                const pathString = String(gameDir);
                if (!pathString) {
                    console.error('gameDir is empty before invoke!');
                    return;
                }
                invoke('update_game_directory', { path: pathString })
                    .catch(error => console.error('❌ Error updating game directory:', error));
            });
            return unlisten;
        };

        setupUnpackListener();
    }, [gameDir]);

    useEffect(() => {
        if (gameDir) {
            // store game directory in persistent storage
            const updateStorage = async (game_dir: string) => {
                try {
                    const store = await load(FILE_STORAGE, { autoSave: true });
                    await store.set(GAME_DIR_KEY, game_dir);
                    console.info(`📦 Storage updated with game directory: ${game_dir}`);
                } catch (error) {
                    console.error('❌ Error updating storage:', error);
                }
            };

            updateStorage(gameDir);

            console.log(`📂 Game directory changed to: ${gameDir}`);
            invoke('update_game_directory', { path: gameDir })
                .catch(error => console.error('❌ Error updating game directory:', error));
        }
    }, [gameDir]);

    useEffect(() => {
        console.log('🔵 Effect starting - setting up listener and requesting games');

        const setupEventListener = async () => {
            try {
                // Listen for games-list-updated events
                const unlisten_games = await listen('games-list-updated', (event) => {
                    console.log('🗲 Received games-list-updated event');
                    const games = event.payload as Game[];
                    console.log(`🎮 ${games.length} Games received`);
                    setGameItems(games);
                    getInitialGameDir();
                });

                // Listen for game-download-begin events
                const unlisten_game_download_begin = await listen('game-download-begin', (event) => {
                    const game_id = event.payload as string;
                    console.log(`🗲 game-download-begin ${game_id} event received`);
                    setGameItems(prev => prev.map(item => item.id === game_id
                        ? { ...item, install_status: InstallStatus.Downloading }
                        : item));
                });

                // Listen for game-download-finished events
                const unlisten_game_download_finished = await listen('game-download-finished', (event) => {
                    const game_id = event.payload as string;
                    console.log(`🗲 game-download-finished ${game_id} event received`);
                    setGameItems(prev => prev.map(item => item.id === game_id
                        ? { ...item, install_status: InstallStatus.Unpacking }
                        : item));
                });

                // Initial request for games
                console.log('📤 Requesting initial games list');
                await invoke('request_games');

                // Cleanup function
                return () => {
                    console.log('🧹 Cleaning up - removing listener');
                    unlisten_games();
                    unlisten_game_download_begin();
                    unlisten_game_download_finished();
                };
            } catch (error) {
                console.error('❌ Error in setup:', error);
            }
        };

        setupEventListener();

        // Cleanup
        return () => {
            console.log('🚫 Effect cleanup - component unmounting');
        };
    }, []); // Empty dependency array means this runs once on mount

    const runGame = async (id: string) => {
        console.log(`🎯 Running game with id=${id}`);
        try {
            const result = await invoke('run_game', { id });
            console.log(`✅ Game started, result=${result}`);
        } catch (error) {
            console.error('❌ Error running game:', error);
        }
    };

    const installGame = async (id: string) => {
        console.log(`🎯 Installing game with id=${id}`);
        try {
            const success = await invoke('install_game', { id });
            if (success) {
                console.log(`✅ Game install for id=${id} started...`);
                // update install status in gameItems for this game
                setGameItems(prev => prev.map(item => item.id === id
                    ? { ...item, install_status: InstallStatus.CheckingServer }
                    : item));
            } else {
                // game is already being installed
                console.warn(`🚧 Game with id=${id} is already being installed`);
            }
        } catch (error) {
            console.error('❌ Error installing game:', error);
        }
    };

    const dialogGameDir = async () => {
        const file = await open({
            multiple: false,
            directory: true,
        });

        if (file) {
            setGameDir(file);
        }
    };

    // Rest of your component remains the same
    return (
        <main className="container">
            <div className="fixed-header">
                <h1 className="align-center">SoftLAN Launcher</h1>
                <div className="main-header">
                    {gameItems.length > 0 ? (
                    <div className="search-settings-wrapper">
                        <div></div>
                        <div className="search-container">
                            <input
                                type="text"
                                placeholder="Search games..."
                                value={searchTerm}
                                onChange={(e) => setSearchTerm(e.target.value)}
                                className="search-input"
                            />
                        </div>
                        <div className="settings-container">
                            <button onClick={dialogGameDir} className="settings-button">Set Game Directory</button>
                            <span className="settings-text">{gameDir}</span>
                        </div>
                    </div>
                    ) : (
                        <div className="search-container">
                        Waiting for connection to server...
                        </div>
                    )}
                </div>
            </div>
            <div className="grid-container">
                {filteredGames.map((item) => {
                    const uint8Array = new Uint8Array(item.thumbnail);
                    const binaryString = uint8Array.reduce((acc, byte) => acc + String.fromCharCode(byte), '');
                    const thumbnailUrl = `data:image/jpeg;base64,${btoa(binaryString)}`;
                    return (
                        <div key={item.id} className="item">
                            <img src={thumbnailUrl} alt={`${item.name} thumbnail`} />
                            <div className="item-name">{item.name}</div>
                            <div className="description">
                                <span className="desc-text">{item.description.slice(0, 10)}</span>
                                <span className="size-text">{(item.size / 1024 / 1024 / 1024).toFixed(1)} GB</span>
                            </div>
                            <div className="play-button"
                                onClick={() => item.installed
                                    ? runGame(item.id)
                                    : installGame(item.id)}>
                                {item.installed ? 'Play'
                                    : item.install_status === InstallStatus.CheckingServer ? 'Checking server...'
                                        : item.install_status === InstallStatus.Downloading ? 'Downloading...'
                                            : item.install_status === InstallStatus.Unpacking ? 'Unpacking...'
                                                : 'Install'}
                            </div>
                        </div>
                    );
                })}
            </div>
        </main>
    );
};

export default App;
