import VersionUpdateModal from '@/components/VersionUpdateModal';
import { useToast } from '@/contexts/ToastContext';
import { fetchVersionInfo, getCurrentAppVersion, type VersionInfo } from '@/services/version';
import { log } from '@/utils/logger';
import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
import { Linking } from 'react-native';
import { useTranslation } from 'react-i18next';

type VersionCheckContextValue = {
  isChecking: boolean;
  updateInfo: VersionInfo | null;
  checkForUpdate: (options?: { manual?: boolean }) => Promise<VersionInfo | null>;
  openStore: () => Promise<void>;
};

const VersionCheckContext = createContext<VersionCheckContextValue | undefined>(undefined);

export function VersionCheckProvider({ children }: { children: React.ReactNode }) {
  const { showSuccess, showError } = useToast();
  const { t } = useTranslation();
  const [isChecking, setIsChecking] = useState(false);
  const [updateInfo, setUpdateInfo] = useState<VersionInfo | null>(null);
  const [modalVisible, setModalVisible] = useState(false);
  const hasAutoCheckedRef = useRef(false);
  const currentVersion = useMemo(() => getCurrentAppVersion(), []);

  const openStore = useCallback(async () => {
    if (!updateInfo?.appStoreUrl) {
      showError(t('personal.versionCheck.missingUrl'));
      return;
    }

    try {
      const supported = await Linking.canOpenURL(updateInfo.appStoreUrl);
      if (!supported) {
        throw new Error('URL not supported');
      }
      await Linking.openURL(updateInfo.appStoreUrl);
      log.info('version-update-open-store', { url: updateInfo.appStoreUrl });
    } catch (error) {
      log.error('version-update-open-store-failed', error);
      showError(t('personal.versionCheck.openStoreFailed'));
    }
  }, [showError, t, updateInfo]);

  const checkForUpdate = useCallback(
    async ({ manual = false }: { manual?: boolean } = {}) => {
      if (isChecking) {
        if (manual) {
          showSuccess(t('personal.versionCheck.checking'));
        }
        return updateInfo;
      }

      setIsChecking(true);
      try {
        const info = await fetchVersionInfo();
        setUpdateInfo(info);
        setModalVisible(Boolean(info?.needsUpdate));

        if (info?.needsUpdate && manual) {
          showSuccess(
            t('personal.versionCheck.updateFound', {
              version: info.latestVersion,
            })
          );
        } else if (!info?.needsUpdate && manual) {
          showSuccess(t('personal.versionCheck.upToDate'));
        }

        return info;
      } catch (error) {
        log.error('version-check-failed', error);
        if (manual) {
          showError(t('personal.versionCheck.failed'));
        }
        return null;
      } finally {
        setIsChecking(false);
      }
    },
    [isChecking, showError, showSuccess, t, updateInfo]
  );

  useEffect(() => {
    if (hasAutoCheckedRef.current) return;
    hasAutoCheckedRef.current = true;
    checkForUpdate({ manual: false }).catch((error) => {
      log.error('auto-version-check-failed', error);
    });
  }, [checkForUpdate]);

  const strings = useMemo(
    () => ({
      title: t('personal.versionCheck.modalTitle'),
      tag: t('personal.versionCheck.modalTag'),
      currentVersionLabel: t('personal.versionCheck.currentVersion'),
      latestVersionLabel: t('personal.versionCheck.latestVersion'),
      updatesTitle: t('personal.versionCheck.releaseNotesTitle'),
      fallbackNote: t('personal.versionCheck.fallbackNotes'),
      remindLater: t('personal.versionCheck.later'),
      updateCta: t('personal.versionCheck.updateNow'),
    }),
    [t]
  );

  return (
    <VersionCheckContext.Provider
      value={{
        isChecking,
        updateInfo,
        checkForUpdate,
        openStore,
      }}
    >
      {children}
      <VersionUpdateModal
        visible={modalVisible && Boolean(updateInfo?.needsUpdate)}
        info={updateInfo}
        currentVersion={currentVersion}
        onClose={() => setModalVisible(false)}
        onUpdate={openStore}
        strings={strings}
      />
    </VersionCheckContext.Provider>
  );
}

export function useVersionCheck(): VersionCheckContextValue {
  const context = useContext(VersionCheckContext);
  if (!context) {
    throw new Error('useVersionCheck must be used within VersionCheckProvider');
  }
  return context;
}
