import React, { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom';

import Button from '@/entrypoints/popup/components/Button';
import PasskeyBypassDialog from '@/entrypoints/popup/components/Dialogs/PasskeyBypassDialog';
import LoadingSpinner from '@/entrypoints/popup/components/LoadingSpinner';
import { useDb } from '@/entrypoints/popup/context/DbContext';
import { useLoading } from '@/entrypoints/popup/context/LoadingContext';
import { useVaultLockRedirect } from '@/entrypoints/popup/hooks/useVaultLockRedirect';

import { LocalPreferencesService } from '@/utils/LocalPreferencesService';
import { sendMessage } from '@/utils/messaging/ExtensionMessaging';
import { buildPasskeyAssertion } from '@/utils/passkey/PasskeyAssertionService';
import { PasskeyHelper } from '@/utils/passkey/PasskeyHelper';
import type { PendingPasskeyGetRequest } from '@/utils/passkey/types';
import { extractDomain } from '@/utils/RustCore';

/**
 * PasskeyAuthenticate
 */
const PasskeyAuthenticate: React.FC = () => {
  const { t } = useTranslation();
  const location = useLocation();
  const { setIsInitialLoading } = useLoading();
  const dbContext = useDb();
  const [request, setRequest] = useState<PendingPasskeyGetRequest | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [availablePasskeys, setAvailablePasskeys] = useState<Array<{ id: string; displayName: string; rpId: string; serviceName?: string | null }>>([]);
  const [showBypassDialog, setShowBypassDialog] = useState(false);
  const { isLocked } = useVaultLockRedirect();
  const firstPasskeyRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    /**
     * fetchRequestData
     */
    const fetchRequestData = async () : Promise<void> => {
      // Wait for DB to be initialized
      if (!dbContext.dbInitialized) {
        return;
      }

      // If vault is locked, the hook will handle redirect, we just return
      if (isLocked) {
        return;
      }

      // Get the requestId from URL
      const params = new URLSearchParams(location.search);
      const requestId = params.get('requestId');

      if (requestId) {
        try {
          // Fetch the full request data from background
          const data = await sendMessage('GET_REQUEST_DATA', { requestId }) as unknown as PendingPasskeyGetRequest;

          if (data && data.type === 'get') {
            setRequest(data);

            // Get passkeys for this rpId from the vault
            const rpId = data.publicKey.rpId || new URL(data.origin).hostname;
            const passkeys = dbContext.sqliteClient!.passkeys.getByRpId(rpId);

            // Filter by allowCredentials if specified
            let filteredPasskeys = passkeys;
            if (data.publicKey.allowCredentials && data.publicKey.allowCredentials.length > 0) {
              // Convert the RP's base64url credential IDs to GUIDs for comparison
              const allowedGuids = new Set(
                data.publicKey.allowCredentials.map((c: { id: string }) => {
                  try {
                    return PasskeyHelper.base64urlToGuid(c.id);
                  } catch (e) {
                    console.warn('Failed to convert credential ID to GUID:', c.id, e);
                    return null;
                  }
                }).filter((id: string | null): id is string => id !== null)
              );
              filteredPasskeys = passkeys.filter((pk: { Id: string }) => allowedGuids.has(pk.Id));
            }

            // Map to display format
            setAvailablePasskeys(filteredPasskeys.map((pk: { Id: string; DisplayName: string; ServiceName?: string | null; RpId: string; Username?: string | null }) => ({
              id: pk.Id,
              displayName: pk.DisplayName,
              serviceName: pk.ServiceName,
              rpId: pk.RpId,
              username: pk.Username
            })));
          }
        } catch (error) {
          console.error('Failed to fetch request data:', error);
          setError(t('common.errors.unknownError'));
        }
      }

      // Mark initial loading as complete
      setIsInitialLoading(false);
    };

    fetchRequestData();
  }, [location, setIsInitialLoading, dbContext.dbInitialized, isLocked, dbContext.sqliteClient, t]);

  // Auto-focus first passkey
  useEffect(() => {
    if (availablePasskeys.length > 0 && firstPasskeyRef.current) {
      firstPasskeyRef.current.focus();
    }
  }, [availablePasskeys.length]);

  // Handle Enter key to select first passkey
  useEffect(() => {
    /**
     * Handle Enter key to select first passkey
     */
    const handleKeyDown = (e: KeyboardEvent) : void => {
      if (e.key === 'Enter' && !loading && availablePasskeys.length > 0) {
        handleUsePasskey(availablePasskeys[0].id);
      }
    };

    /**
     * Handle Enter key to select first passkey
     */
    window.addEventListener('keydown', handleKeyDown);
    return () : void => window.removeEventListener('keydown', handleKeyDown);

    /**
     * Handle Enter key to select first passkey
     */
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [loading, availablePasskeys]);

  /**
   * Handle passkey authentication
   */
  const handleUsePasskey = async (passkeyId: string) : Promise<void> => {
    if (!request || !dbContext.sqliteClient) {
      return;
    }

    setLoading(true);
    setError(null);

    try {
      // Build the assertion from the selected passkey using the shared service.
      const credential = await buildPasskeyAssertion(dbContext.sqliteClient, request, passkeyId);

      /*
       * Send response back
       * The background script will close the window (Safari-compatible)
       */
      await sendMessage('PASSKEY_POPUP_RESPONSE', {
        requestId: request.requestId,
        credential
      });
    } catch (error) {
      console.error('PasskeyAuthenticate: Error during authentication', error);
      setLoading(false);
      setError(t('common.errors.unknownError'));
    }
  };

  /**
   * Handle fallback - show bypass dialog first
   */
  const handleFallback = async () : Promise<void> => {
    setShowBypassDialog(true);
  };

  /**
   * Handle bypass choice
   */
  const handleBypassChoice = async (choice: 'once' | 'always') : Promise<void> => {
    if (!request) {
      return;
    }

    if (choice === 'always') {
      // Add to permanent disabled list (for this specific subdomain)
      const domain = await extractDomain(request.origin);

      const disabledSites = await LocalPreferencesService.getPasskeyDisabledSites();
      if (!disabledSites.includes(domain)) {
        disabledSites.push(domain);
        await LocalPreferencesService.setPasskeyDisabledSites(disabledSites);
      }
    }
    // For 'once', we don't store anything - just bypass this one time

    /*
     * Tell background to use native implementation
     * The background script will close the window (Safari-compatible)
     */
    await sendMessage('PASSKEY_POPUP_RESPONSE', {
      requestId: request.requestId,
      fallback: true
    });
  };

  /**
   * Handle cancel
   */
  const handleCancel = async () : Promise<void> => {
    if (!request) {
      return;
    }

    /*
     * Tell background user cancelled
     * The background script will close the window (Safari-compatible)
     */
    await sendMessage('PASSKEY_POPUP_RESPONSE', {
      requestId: request.requestId,
      cancelled: true
    });
  };

  if (!request) {
    return (
      <div className="flex justify-center py-8">
        <LoadingSpinner />
      </div>
    );
  }

  return (
    <>
      <PasskeyBypassDialog
        isOpen={showBypassDialog && !!request}
        origin={request ? new URL(request.origin).hostname : ''}
        onChoice={handleBypassChoice}
        onCancel={() => setShowBypassDialog(false)}
      />

      <div className="space-y-6">
        <div className="text-center">
          <h1 className="text-xl font-semibold text-gray-900 dark:text-white mb-2">
            {t('passkeys.authenticate.title')}
          </h1>
          <p className="text-sm text-gray-600 dark:text-gray-400">
            {t('passkeys.authenticate.signInFor')} <strong>{request.origin}</strong>
          </p>
        </div>

        {error && (
          <div className="p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg">
            <p className="text-sm text-red-800 dark:text-red-200">{error}</p>
          </div>
        )}

        <div className="space-y-4">
          {availablePasskeys && availablePasskeys.length > 0 ? (
            <div className="space-y-2">
              <label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
                {t('passkeys.authenticate.selectPasskey')}
              </label>
              <div className="space-y-2 max-h-48 overflow-y-auto border rounded-lg p-2 bg-gray-50 dark:bg-gray-800">
                {availablePasskeys.map((pk, index) => (
                  <div
                    key={pk.id}
                    ref={index === 0 ? firstPasskeyRef : null}
                    tabIndex={0}
                    className="p-3 rounded-lg border cursor-pointer transition-colors bg-white border-gray-200 hover:bg-gray-100 hover:border-gray-300 dark:bg-gray-700 dark:border-gray-600 dark:hover:bg-gray-600 dark:hover:border-gray-500 focus:outline-none focus:ring-1 focus:ring-primary-500 focus:border-primary-500"
                    onClick={() => !loading && handleUsePasskey(pk.id)}
                    onKeyDown={(e) => {
                      if (e.key === 'Enter' && !loading) {
                        handleUsePasskey(pk.id);
                      }
                    }}
                  >
                    <div className="font-medium text-gray-900 dark:text-white text-sm truncate">
                      {pk.serviceName}
                    </div>
                    <div className="flex items-center justify-between text-xs text-gray-600 dark:text-gray-400">
                      <span className="truncate">{pk.displayName}</span>
                    </div>
                  </div>
                ))}
              </div>
            </div>
          ) : (
            <div className="text-center py-8 bg-gray-50 dark:bg-gray-800 rounded-lg">
              <p className="text-gray-600 dark:text-gray-400">
                {t('passkeys.authenticate.noPasskeysFound')}
              </p>
            </div>
          )}
        </div>

        <div className="space-y-3">
          <Button
            variant="secondary"
            onClick={handleFallback}
          >
            {t('passkeys.useBrowserPasskey')}
          </Button>

          <Button
            variant="secondary"
            onClick={handleCancel}
          >
            {t('common.cancel')}
          </Button>
        </div>
      </div>
    </>
  );
};

export default PasskeyAuthenticate;
