import { useState, useEffect } from 'react';
import { AppShell, Loader, Center, Stack, Text } from '@mantine/core';
import { DownloadScreen } from '@/components/screens/Download';
import { LaunchScreen } from '@/components/screens/Launch';
import { InterfaceScreen } from '@/components/screens/Interface';
import { WelcomeScreen } from '@/components/screens/Welcome';
import { UpdateAvailableModal } from '@/components/UpdateAvailableModal';
import { SettingsModal } from '@/components/settings/SettingsModal';
import { EjectConfirmModal } from '@/components/EjectConfirmModal';
import { ScreenTransition } from '@/components/ScreenTransition';
import { AppHeader } from '@/components/AppHeader';
import { useUpdateChecker } from '@/hooks/useUpdateChecker';
import { useKoboldVersions } from '@/hooks/useKoboldVersions';
import { UI } from '@/constants';
import { Logger } from '@/utils/logger';
import type { DownloadItem } from '@/types/electron';
import type { InterfaceTab, FrontendPreference, Screen } from '@/types';

export const App = () => {
  const [currentScreen, setCurrentScreen] = useState<Screen | null>(null);
  const [settingsOpened, setSettingsOpened] = useState(false);
  const [hasInitialized, setHasInitialized] = useState(false);
  const [showEjectModal, setShowEjectModal] = useState(false);
  const [activeInterfaceTab, setActiveInterfaceTab] =
    useState<InterfaceTab>('terminal');
  const [isImageGenerationMode, setIsImageGenerationMode] = useState(false);
  const [frontendPreference, setFrontendPreference] =
    useState<FrontendPreference>('koboldcpp');

  const {
    updateInfo: binaryUpdateInfo,
    showUpdateModal,
    checkForUpdates,
    dismissUpdate,
  } = useUpdateChecker();

  const {
    handleDownload: sharedHandleDownload,
    downloading,
    downloadProgress,
  } = useKoboldVersions();

  const setCurrentScreenWithTransition = (screen: Screen) => {
    setCurrentScreen(screen);
  };

  useEffect(() => {
    const checkInstallation = async () => {
      await Logger.safeExecute(async () => {
        const [currentVersion, hasSeenWelcome, preference] = await Promise.all([
          window.electronAPI.kobold.getCurrentVersion(),
          window.electronAPI.config.get('hasSeenWelcome') as Promise<boolean>,
          window.electronAPI.config.get(
            'frontendPreference'
          ) as Promise<FrontendPreference>,
        ]);

        setFrontendPreference(preference || 'koboldcpp');

        if (!hasSeenWelcome) {
          setCurrentScreenWithTransition('welcome');
        } else if (currentVersion) {
          setCurrentScreenWithTransition('launch');
        } else {
          setCurrentScreenWithTransition('download');
        }

        if (currentVersion) {
          setTimeout(() => {
            checkForUpdates();
          }, 2000);
        }
      }, 'Error checking installation:');

      setHasInitialized(true);
    };

    checkInstallation();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const handleBinaryUpdate = async (download: DownloadItem) => {
    await Logger.safeExecute(async () => {
      const success = await sharedHandleDownload({
        item: download,
        isUpdate: true,
        wasCurrentBinary: true,
      });

      if (success) {
        dismissUpdate();
      }
    }, 'Failed to update binary:');
  };

  const handleDownloadComplete = async () => {
    await Logger.safeExecute(async () => {
      await window.electronAPI.kobold.getCurrentVersion();
    }, 'Error refreshing versions after download:');

    setTimeout(() => {
      setCurrentScreenWithTransition('launch');
    }, 100);
  };

  const handleLaunch = () => {
    setActiveInterfaceTab('terminal');
    setCurrentScreenWithTransition('interface');
  };

  const handleBackToLaunch = () => {
    setCurrentScreenWithTransition('launch');
  };

  const handleEject = async () => {
    const skipEjectConfirmation = await window.electronAPI.config.get(
      'skipEjectConfirmation'
    );

    if (skipEjectConfirmation) {
      performEject();
    } else {
      setShowEjectModal(true);
    }
  };

  const performEject = () => {
    window.electronAPI.kobold.stopKoboldCpp();
    handleBackToLaunch();
  };

  const handleEjectConfirm = async (skipConfirmation: boolean) => {
    if (skipConfirmation) {
      await window.electronAPI.config.set('skipEjectConfirmation', true);
    }
    performEject();
  };

  const handleWelcomeComplete = async () => {
    await window.electronAPI.config.set('hasSeenWelcome', true);

    const versions = await window.electronAPI.kobold.getInstalledVersions();
    if (versions.length > 0) {
      setCurrentScreenWithTransition('launch');
    } else {
      setCurrentScreenWithTransition('download');
    }
  };

  return (
    <AppShell
      header={{ height: currentScreen === 'welcome' ? 0 : UI.HEADER_HEIGHT }}
      padding={currentScreen === 'interface' ? 0 : 'md'}
    >
      {currentScreen !== 'welcome' && (
        <AppHeader
          currentScreen={currentScreen}
          activeInterfaceTab={activeInterfaceTab}
          setActiveInterfaceTab={setActiveInterfaceTab}
          isImageGenerationMode={isImageGenerationMode}
          frontendPreference={frontendPreference}
          onEject={handleEject}
          onSettingsOpen={() => setSettingsOpened(true)}
        />
      )}
      <AppShell.Main
        style={{
          position: 'relative',
          overflow: 'hidden',
          minHeight:
            currentScreen === 'welcome'
              ? '100vh'
              : `calc(100vh - ${UI.HEADER_HEIGHT}px)`,
        }}
      >
        {currentScreen === null ? (
          <Center h="100%" style={{ minHeight: '25rem' }}>
            <Stack align="center" gap="lg">
              <Loader size="xl" type="dots" />
              <Text c="dimmed" size="lg">
                Loading...
              </Text>
            </Stack>
          </Center>
        ) : (
          <>
            <ScreenTransition
              isActive={currentScreen === 'welcome'}
              shouldAnimate={hasInitialized}
            >
              <WelcomeScreen onGetStarted={handleWelcomeComplete} />
            </ScreenTransition>

            <ScreenTransition
              isActive={currentScreen === 'download'}
              shouldAnimate={hasInitialized}
            >
              <DownloadScreen onDownloadComplete={handleDownloadComplete} />
            </ScreenTransition>

            <ScreenTransition
              isActive={currentScreen === 'launch'}
              shouldAnimate={hasInitialized}
            >
              <LaunchScreen
                onLaunch={handleLaunch}
                onLaunchModeChange={setIsImageGenerationMode}
              />
            </ScreenTransition>

            <ScreenTransition
              isActive={currentScreen === 'interface'}
              shouldAnimate={hasInitialized}
            >
              <InterfaceScreen
                activeTab={activeInterfaceTab}
                onTabChange={setActiveInterfaceTab}
                isImageGenerationMode={isImageGenerationMode}
                frontendPreference={frontendPreference}
              />
            </ScreenTransition>
          </>
        )}

        {showUpdateModal && binaryUpdateInfo && (
          <UpdateAvailableModal
            opened={showUpdateModal}
            onClose={dismissUpdate}
            currentVersion={binaryUpdateInfo.currentVersion}
            availableUpdate={binaryUpdateInfo.availableUpdate}
            onUpdate={handleBinaryUpdate}
            isDownloading={
              downloading === binaryUpdateInfo.availableUpdate.name
            }
            downloadProgress={
              downloadProgress[binaryUpdateInfo.availableUpdate.name] || 0
            }
          />
        )}
      </AppShell.Main>
      <SettingsModal
        opened={settingsOpened}
        onClose={async () => {
          setSettingsOpened(false);
          const preference = await Logger.safeExecute(
            () =>
              window.electronAPI.config.get(
                'frontendPreference'
              ) as Promise<FrontendPreference>,
            'Failed to load frontend preference:'
          );
          setFrontendPreference(preference || 'koboldcpp');
        }}
        currentScreen={currentScreen || undefined}
      />
      <EjectConfirmModal
        opened={showEjectModal}
        onClose={() => setShowEjectModal(false)}
        onConfirm={handleEjectConfirm}
      />
    </AppShell>
  );
};
