import { useEffect, useState } from 'react';

import { getBackendUrl } from '../../services/backendUrl';
import { getDeepLinkAuthState } from '../../store/deepLinkAuthState';
import type { OAuthProviderConfig } from '../../types/oauth';
import { IS_DEV } from '../../utils/config';
import { openUrl } from '../../utils/openUrl';
import { isTauri } from '../../utils/tauriCommands';

interface OAuthProviderButtonProps {
  provider: OAuthProviderConfig;
  className?: string;
  disabled?: boolean;
  onClickOverride?: () => void;
}

// Reset the loading state if the OAuth round-trip never completes — covers
// the case where the user cancels in the system browser, or the backend
// redirect fails so the `openhuman://` deep link never fires.
const OAUTH_LOADING_TIMEOUT_MS = 90_000;

const getOAuthStartupFailureMessage = (provider: OAuthProviderConfig): string => {
  if (provider.id === 'twitter') {
    return 'Twitter/X sign-in could not start. Check that the Twitter OAuth app callback URL, client ID/secret, and requested scopes match the OpenHuman backend, then try again.';
  }

  return `${provider.name} sign-in could not start. Please try again.`;
};

const summarizeOAuthStartupError = (error: unknown): string => {
  if (!(error instanceof Error)) {
    return typeof error;
  }

  // Keep diagnostics useful without leaking URLs or query parameters from host
  // opener errors.
  const redactedMessage = error.message
    .replace(/https?:\/\/\S+/g, '[redacted-url]')
    .replace(/openhuman:\/\/\S+/g, '[redacted-deep-link]');

  return `${error.name}: ${redactedMessage.slice(0, 160)}`;
};

const OAuthProviderButton = ({
  provider,
  className = '',
  disabled: externalDisabled = false,
  onClickOverride,
}: OAuthProviderButtonProps) => {
  const [isLoading, setIsLoading] = useState(false);
  const [startupError, setStartupError] = useState<string | null>(null);

  useEffect(() => {
    if (!isLoading) return;

    const reset = () => setIsLoading(false);

    // Skip reset when a deep-link auth round-trip is already in flight — the
    // OAuth callback flips `isProcessing=true` AFTER the OS focus event fires,
    // and resetting first would briefly re-enable the button mid-redirect.
    const skipDuringDeepLink = (label: string) => {
      if (getDeepLinkAuthState().isProcessing) {
        console.debug(`[oauth-button][${provider.id}] ${label} — skip (deep-link processing)`);
        return true;
      }
      return false;
    };

    // Fast path: window focus fires when the user returns from the system
    // browser. On most platforms this lifts the loading state immediately.
    const handleFocus = () => {
      if (skipDuringDeepLink('focus')) return;
      console.debug(`[oauth-button][${provider.id}] window focus → reset isLoading`);
      reset();
    };

    // Backup path: macOS Spaces / virtual desktops sometimes restore window
    // focus without firing a `focus` event. `visibilitychange` is the more
    // reliable signal there.
    const handleVisibilityChange = () => {
      if (document.visibilityState !== 'visible') return;
      if (skipDuringDeepLink('visibilitychange')) return;
      console.debug(`[oauth-button][${provider.id}] visibilitychange visible → reset isLoading`);
      reset();
    };

    const timer = window.setTimeout(() => {
      console.debug(`[oauth-button][${provider.id}] timeout → reset isLoading`);
      reset();
    }, OAUTH_LOADING_TIMEOUT_MS);

    window.addEventListener('focus', handleFocus);
    document.addEventListener('visibilitychange', handleVisibilityChange);

    return () => {
      window.clearTimeout(timer);
      window.removeEventListener('focus', handleFocus);
      document.removeEventListener('visibilitychange', handleVisibilityChange);
    };
  }, [isLoading, provider.id]);

  const handleOAuthLogin = async () => {
    if (onClickOverride) {
      onClickOverride();
      return;
    }

    if (externalDisabled || isLoading) return;

    console.debug(`[oauth-button][${provider.id}] starting OAuth login (isTauri=${isTauri()})`);

    setStartupError(null);
    setIsLoading(true);

    try {
      const backendUrl = await getBackendUrl();
      const loginUrl = `${backendUrl}/auth/${provider.id}/login${IS_DEV ? '?responseType=json' : ''}`;

      if (IS_DEV) {
        console.log(`[dev] OAuth debug mode enabled. OAuth URL: ${loginUrl}`);
        console.log('[dev] In debug mode, OAuth will return JSON response instead of redirect.');
        console.log(
          '[dev] After OAuth completion, copy the loginToken and use: window.__simulateDeepLink("openhuman://auth?token=YOUR_TOKEN")'
        );
      }

      // Desktop (Tauri): use system browser → backend OAuth → deep link back to app
      if (isTauri()) {
        await openUrl(loginUrl);
      } else {
        // Web fallback: direct OAuth flow in current window
        window.location.href = loginUrl;
      }
    } catch (error) {
      const message = getOAuthStartupFailureMessage(provider);
      console.error(`[oauth-button][${provider.id}] OAuth startup failed`, {
        provider: provider.id,
        providerName: provider.name,
        reason: summarizeOAuthStartupError(error),
        guidance: message,
      });
      setStartupError(message);
      setIsLoading(false);
    }
  };

  const isDisabled = externalDisabled || isLoading;
  const IconComponent = provider.icon;

  return (
    <div className="min-w-0">
      <button
        onClick={handleOAuthLogin}
        disabled={isDisabled}
        className={`flex min-w-0 items-center justify-center space-x-3 ${provider.color} ${provider.hoverColor} text-sm font-medium py-2.5 px-4 rounded-xl transition-all duration-300 hover:shadow-medium hover:scale-[1.02] active:scale-[0.98] disabled:hover:scale-100 disabled:opacity-50 disabled:cursor-not-allowed ${className}`}>
        {isLoading ? (
          <div className="animate-spin rounded-full h-5 w-5 border-b-2 border-current"></div>
        ) : (
          <IconComponent className="w-5 h-5" />
        )}
        <span className={provider.textColor}>{isLoading ? 'Connecting...' : provider.name}</span>
      </button>
      {startupError ? (
        <p role="alert" className="mt-2 text-xs leading-5 text-red-600">
          {startupError}
        </p>
      ) : null}
    </div>
  );
};

export default OAuthProviderButton;
