import React, { useState, useEffect, useRef, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import * as Yup from 'yup';

import LanguageSwitcher from '@/entrypoints/popup/components/LanguageSwitcher';
import { useLoading } from '@/entrypoints/popup/context/LoadingContext';

import { AppInfo } from '@/utils/AppInfo';
import { LocalPreferencesService } from '@/utils/LocalPreferencesService';

import { storage } from '#imports';

type ApiOption = {
  label: string;
  value: string;
};

const DEFAULT_OPTIONS: ApiOption[] = [
  { label: 'Aliasvault.net', value: AppInfo.DEFAULT_API_URL },
  { label: 'Self-hosted', value: 'custom' }
];

// Validation schema for URLs
/**
 * Creates a URL validation schema with localized error messages.
 */
const createUrlSchema = (t: (key: string) => string): Yup.ObjectSchema<{apiUrl: string; clientUrl: string}> => Yup.object().shape({
  apiUrl: Yup.string()
    .required(t('settings.validation.apiUrlRequired'))
    .test('is-valid-api-url', t('settings.validation.apiUrlInvalid'), (value: string | undefined) => {
      if (!value) {
        return true; // Allow empty for non-custom option
      }
      try {
        const url = new URL(value);
        return url.protocol === 'http:' || url.protocol === 'https:';
      } catch {
        return false;
      }
    }),
  clientUrl: Yup.string()
    .required(t('settings.validation.clientUrlRequired'))
    .test('is-valid-client-url', t('settings.validation.clientUrlInvalid'), (value: string | undefined) => {
      if (!value) {
        return true; // Allow empty for non-custom option
      }
      try {
        const url = new URL(value);
        return url.protocol === 'http:' || url.protocol === 'https:';
      } catch {
        return false;
      }
    })
});

/**
 * Auth settings page only shown when user is not logged in.
 */
const AuthSettings: React.FC = () => {
  const { t } = useTranslation();
  const [selectedOption, setSelectedOption] = useState<string>('');
  const [customUrl, setCustomUrl] = useState<string>('');
  const [customClientUrl, setCustomClientUrl] = useState<string>('');
  const [isGloballyEnabled, setIsGloballyEnabled] = useState<boolean>(true);
  const [errors, setErrors] = useState<{ apiUrl?: string; clientUrl?: string }>({});
  const { setIsInitialLoading } = useLoading();

  const urlSchema = createUrlSchema(t);
  const apiUrlDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const clientUrlDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  // Track pending values that haven't been saved yet due to debounce
  const pendingApiUrlRef = useRef<string | null>(null);
  const pendingClientUrlRef = useRef<string | null>(null);

  // Flush pending saves and clean up on unmount (when navigating away)
  useEffect((): (() => void) => {
    return (): void => {
      // Clear debounce timers
      if (apiUrlDebounceRef.current) {
        clearTimeout(apiUrlDebounceRef.current);
      }
      if (clientUrlDebounceRef.current) {
        clearTimeout(clientUrlDebounceRef.current);
      }

      // Save any pending values synchronously before unmount
      if (pendingApiUrlRef.current !== null) {
        const value = pendingApiUrlRef.current;
        storage.setItem('local:apiUrl', value);
      }
      if (pendingClientUrlRef.current !== null) {
        const value = pendingClientUrlRef.current;
        storage.setItem('local:clientUrl', value);
      }
    };
  }, []);

  useEffect(() => {
    /**
     * Load the stored settings from the storage.
     */
    const loadStoredSettings = async () : Promise<void> => {
      const apiUrl = await storage.getItem('local:apiUrl') as string;
      const clientUrl = await storage.getItem('local:clientUrl') as string;
      const globallyEnabled = await LocalPreferencesService.getGlobalAutofillPopupEnabled();
      const dismissUntil = await LocalPreferencesService.getVaultLockedDismissUntil();

      if (dismissUntil) {
        setIsGloballyEnabled(false);
      } else {
        setIsGloballyEnabled(globallyEnabled);
      }

      const matchingOption = DEFAULT_OPTIONS.find(opt => opt.value === apiUrl);

      if (matchingOption) {
        setSelectedOption(matchingOption.value);
      } else if (apiUrl) {
        setSelectedOption('custom');
        setCustomUrl(apiUrl);
        setCustomClientUrl(clientUrl ?? '');
      } else {
        setSelectedOption(DEFAULT_OPTIONS[0].value);
      }
      setIsInitialLoading(false);
    };

    loadStoredSettings();
  }, [setIsInitialLoading]);

  /**
   * Handle option change
   */
  const handleOptionChange = async (e: React.ChangeEvent<HTMLSelectElement>) : Promise<void> => {
    const value = e.target.value;
    setSelectedOption(value);
    if (value !== 'custom') {
      await storage.setItem('local:apiUrl', '');
      await storage.setItem('local:clientUrl', '');
      setCustomUrl('');
      setCustomClientUrl('');
      setErrors({});
    }
  };

  /**
   * Handle custom API URL change.
   * Updates UI state immediately but debounces validation and storage writes to prevent concurrency issues.
   */
  const handleCustomUrlChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) : void => {
    const value = e.target.value;
    setCustomUrl(value);
    pendingApiUrlRef.current = value;

    if (apiUrlDebounceRef.current) {
      clearTimeout(apiUrlDebounceRef.current);
    }

    apiUrlDebounceRef.current = setTimeout(async () => {
      try {
        await urlSchema.validateAt('apiUrl', { apiUrl: value });
        setErrors(prev => ({ ...prev, apiUrl: undefined }));
        await storage.setItem('local:apiUrl', value);
        pendingApiUrlRef.current = null;
      } catch (error: unknown) {
        if (error instanceof Yup.ValidationError) {
          setErrors(prev => ({ ...prev, apiUrl: error.message }));
          // On error we revert back to the aliasvault.net official hosted instance.
          await storage.setItem('local:apiUrl', AppInfo.DEFAULT_API_URL);
          await storage.setItem('local:clientUrl', AppInfo.DEFAULT_CLIENT_URL);
          pendingApiUrlRef.current = null;
        }
      }
    }, 150);
  }, [urlSchema]);

  /**
   * Handle custom client URL change.
   * Updates UI state immediately but debounces validation and storage writes to prevent concurrency issues.
   */
  const handleCustomClientUrlChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) : void => {
    const value = e.target.value;
    setCustomClientUrl(value);
    pendingClientUrlRef.current = value;

    if (clientUrlDebounceRef.current) {
      clearTimeout(clientUrlDebounceRef.current);
    }

    clientUrlDebounceRef.current = setTimeout(async () => {
      try {
        await urlSchema.validateAt('clientUrl', { clientUrl: value });
        setErrors(prev => ({ ...prev, clientUrl: undefined }));
        await storage.setItem('local:clientUrl', value);
        pendingClientUrlRef.current = null;
      } catch (error: unknown) {
        if (error instanceof Yup.ValidationError) {
          setErrors(prev => ({ ...prev, clientUrl: error.message }));
          pendingClientUrlRef.current = null;
        }
      }
    }, 150);
  }, [urlSchema]);

  /**
   * Toggle global popup.
   */
  const toggleGlobalPopup = async () : Promise<void> => {
    const newGloballyEnabled = !isGloballyEnabled;

    await LocalPreferencesService.setGlobalAutofillPopupEnabled(newGloballyEnabled);

    if (newGloballyEnabled) {
      // Reset all disabled sites when enabling globally
      await LocalPreferencesService.setDisabledSites([]);
      await LocalPreferencesService.setVaultLockedDismissUntil(0);
    }

    setIsGloballyEnabled(newGloballyEnabled);
  };

  return (
    <div className="p-4 space-y-6">
      {/* Server Configuration Section */}
      <div className="space-y-4 pb-6 border-b border-gray-200 dark:border-gray-700">
        <div>
          <h2 className="text-lg font-semibold text-gray-900 dark:text-white mb-1">
            {t('settings.serverConfiguration', 'Server Configuration')}
          </h2>
          <p className="text-sm text-gray-500 dark:text-gray-400">
            {t('settings.serverConfigurationDescription', 'Configure the AliasVault server URL for self-hosted instances')}
          </p>
        </div>

        <div>
          <label htmlFor="api-connection" className="block text-sm font-medium text-gray-700 dark:text-gray-200 mb-2">
            {t('settings.serverUrl')}
          </label>
          <select
            id="api-connection"
            value={selectedOption}
            onChange={handleOptionChange}
            className="w-full bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white"
          >
            {DEFAULT_OPTIONS.map(option => (
              <option key={option.value} value={option.value}>
                {option.label}
              </option>
            ))}
          </select>
        </div>

        {selectedOption === 'custom' && (
          <div className="space-y-4 pl-4 border-l-2 border-primary-500">
            <div>
              <label htmlFor="custom-api-url" className="block text-sm font-medium text-gray-700 dark:text-gray-200 mb-2">
                {t('settings.customApiUrl', 'API URL')}
              </label>
              <input
                id="custom-api-url"
                type="text"
                value={customUrl}
                onChange={handleCustomUrlChange}
                placeholder="https://vault.example.com/api"
                className={`w-full bg-gray-50 border ${errors.apiUrl ? 'border-red-500' : 'border-gray-300'} text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white`}
              />
              {errors.apiUrl && (
                <p className="mt-1 text-sm text-red-500">{errors.apiUrl}</p>
              )}
              <p className="mt-1 text-xs text-gray-500 dark:text-gray-400">
                {t('settings.apiUrlHint', 'The API endpoint URL (usually client URL + /api)')}
              </p>
            </div>

            <div>
              <label htmlFor="custom-client-url" className="block text-sm font-medium text-gray-700 dark:text-gray-200 mb-2">
                {t('settings.customClientUrl', 'Client URL')}
              </label>
              <input
                id="custom-client-url"
                type="text"
                value={customClientUrl}
                onChange={handleCustomClientUrlChange}
                placeholder="https://vault.example.com"
                className={`w-full bg-gray-50 border ${errors.clientUrl ? 'border-red-500' : 'border-gray-300'} text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white`}
              />
              {errors.clientUrl && (
                <p className="mt-1 text-sm text-red-500">{errors.clientUrl}</p>
              )}
              <p className="mt-1 text-xs text-gray-500 dark:text-gray-400">
                {t('settings.clientUrlHint', 'The web interface URL of your self-hosted instance')}
              </p>
            </div>
          </div>
        )}
      </div>

      {/* Autofill Settings Section */}
      <div className="space-y-4 pb-6 border-b border-gray-200 dark:border-gray-700">
        <div>
          <h2 className="text-lg font-semibold text-gray-900 dark:text-white mb-1">
            {t('settings.autofillSettings', 'Autofill Settings')}
          </h2>
          <p className="text-sm text-gray-500 dark:text-gray-400">
            {t('settings.autofillSettingsDescription', 'Enable or disable the autofill popup on web pages')}
          </p>
        </div>

        <div className="flex items-center justify-between gap-4">
          <div>
            <p className="text-sm font-medium text-gray-900 dark:text-white">{t('settings.autofillEnabled')}</p>
            <p className="text-xs text-gray-500 dark:text-gray-400">
              {isGloballyEnabled
                ? t('settings.autofillEnabledDescription', 'Autofill suggestions will appear on login forms')
                : t('settings.autofillDisabledDescription', 'Autofill suggestions are disabled globally')
              }
            </p>
          </div>
          <button
            onClick={toggleGlobalPopup}
            className={`px-4 py-2 rounded-md transition-colors font-medium text-sm ${
              isGloballyEnabled
                ? 'bg-green-200 text-green-800 hover:bg-green-300 dark:bg-green-900/30 dark:text-green-400 dark:hover:bg-green-900/50'
                : 'bg-red-200 text-red-800 hover:bg-red-300 dark:bg-red-900/30 dark:text-red-400 dark:hover:bg-red-900/50'
            }`}
          >
            {isGloballyEnabled ? t('common.enabled', 'Enabled') : t('common.disabled', 'Disabled')}
          </button>
        </div>
      </div>

      {/* Language Settings Section */}
      <div className="space-y-4 pb-6">
        <div>
          <h2 className="text-lg font-semibold text-gray-900 dark:text-white mb-1">
            {t('settings.languageSettings', 'Language')}
          </h2>
        </div>

        <div>
          <LanguageSwitcher variant="dropdown" size="sm" />
        </div>
      </div>

      {/* Version Info */}
      <div className="text-center text-xs text-gray-400 dark:text-gray-600 pt-4 border-t border-gray-200 dark:border-gray-700">
        {t('settings.version')}: {AppInfo.VERSION}
      </div>
    </div>
  );
};

export default AuthSettings;
