import { useEffect, useState } from 'react';
import { useForm, Controller, useFormState } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { ExternalLink } from 'lucide-react';
import {
  Button,
  CopyButton,
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  Input,
  Switch,
} from '@insforge/ui';
import WarningIcon from '#assets/icons/warning.svg';
import {
  oAuthConfigSchema,
  OAuthConfigSchema,
  OAuthProvidersSchema,
} from '@insforge/shared-schemas';
import { type OAuthProviderInfo } from '#features/auth/helpers';
import { SecretInput } from './SecretInput';
import { useOAuthConfig } from '#features/auth/hooks/useOAuthConfig';
import { getBackendUrl, isInsForgeCloudProject } from '#lib/utils/utils';

const getCallbackUrl = (provider?: string) => {
  // Use backend API URL for OAuth callback
  let backendUrl = getBackendUrl();

  // Check if backend URL contains "localhost" and provider is "x"
  if (provider === 'x' && backendUrl.includes('localhost')) {
    backendUrl = backendUrl.replace('://localhost', '://www.localhost');
  }
  return `${backendUrl}/api/auth/oauth/${provider}/callback`;
};

interface OAuthConfigDialogProps {
  provider?: OAuthProviderInfo;
  mode: 'create' | 'edit';
  isOpen: boolean;
  onClose: () => void;
  onSuccess?: () => void;
}

export type OAuthDialogMode = OAuthConfigDialogProps['mode'];

export function OAuthConfigDialog({
  provider,
  mode,
  isOpen,
  onClose,
  onSuccess,
}: OAuthConfigDialogProps) {
  const { providerConfig, createConfig, updateConfig, isCreating, isUpdating, isLoadingProvider } =
    useOAuthConfig(mode === 'edit' ? provider?.id : null);

  const form = useForm<OAuthConfigSchema & { clientSecret?: string }>({
    resolver: zodResolver(oAuthConfigSchema.extend({ clientSecret: z.string().optional() })),
    defaultValues: {
      provider: provider?.id || 'google',
      clientId: '',
      clientSecret: '',
      useSharedKey: false,
    },
  });

  const useSharedKey = form.watch('useSharedKey');
  const clientId = form.watch('clientId');
  const clientSecret = form.watch('clientSecret');
  const [isClientSecretVisible, setIsClientSecretVisible] = useState(false);

  // Our Cloud only support shared keys of these OAuth Providers for now
  const sharedKeyProviders: readonly OAuthProvidersSchema[] = [
    'google',
    'github',
    'discord',
    'linkedin',
    'facebook',
    'apple',
    'microsoft',
  ] satisfies readonly OAuthProvidersSchema[];
  const isSharedKeysAvailable =
    isInsForgeCloudProject() && provider?.id && sharedKeyProviders.includes(provider.id);

  // Use useFormState hook for better reactivity
  const { isDirty } = useFormState({
    control: form.control,
  });

  useEffect(() => {
    if (isOpen) {
      setIsClientSecretVisible(false);
    }
  }, [isOpen, provider?.id]);

  // Load OAuth configuration after fetching
  useEffect(() => {
    if (!isOpen || !provider) {
      return;
    }

    if (mode === 'create') {
      form.reset({
        provider: provider.id,
        clientId: '',
        clientSecret: '',
        useSharedKey: isSharedKeysAvailable,
      });
      return;
    }

    if (!isLoadingProvider && providerConfig) {
      form.reset({
        provider: provider.id,
        clientId: providerConfig.clientId || '',
        clientSecret: providerConfig.clientSecret || '',
        useSharedKey: providerConfig.useSharedKey || false,
      });
    }
  }, [form, isLoadingProvider, isOpen, isSharedKeysAvailable, mode, provider, providerConfig]);

  const handleSubmitData = (data: OAuthConfigSchema & { clientSecret?: string }) => {
    if (!provider) {
      return;
    }

    try {
      if (mode === 'edit') {
        if (!providerConfig) {
          return;
        }

        // Update existing config
        updateConfig({
          provider: provider.id,
          config: data.useSharedKey
            ? { useSharedKey: true }
            : {
                clientId: data.clientId,
                clientSecret: data.clientSecret,
                useSharedKey: false,
              },
        });
      } else {
        // Create new config
        createConfig({
          provider: provider.id,
          clientId: data.useSharedKey ? undefined : data.clientId,
          clientSecret: data.useSharedKey ? undefined : clientSecret,
          useSharedKey: data.useSharedKey,
        });
      }

      // Call success callback if provided
      if (onSuccess) {
        onSuccess();
      }
      // Close dialog
      onClose();
    } catch (error) {
      console.error('Error saving OAuth config:', error);
    }
  };

  const handleSubmit = () => {
    void handleSubmitData(form.getValues());
  };

  const saving = isCreating || isUpdating;

  // Use RHF's built-in validation and dirty state
  const isDisabled = () => {
    if (saving) {
      return true;
    }

    // In update mode, require dirty state
    if (mode === 'edit') {
      if (!providerConfig || !isDirty) {
        return true;
      }
    }

    // If using shared keys, always allow (no credential validation needed)
    if (useSharedKey) {
      return false;
    }

    // If NOT using shared keys, require both clientId and clientSecret
    return !clientId || !clientSecret;
  };

  return (
    <Dialog open={isOpen && !!provider} onOpenChange={(open) => !open && onClose()}>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>{provider?.name}</DialogTitle>
          <DialogDescription className="sr-only">
            Configure OAuth settings for {provider?.name}
          </DialogDescription>
        </DialogHeader>
        {isLoadingProvider ? (
          <div className="p-6 flex items-center justify-center">
            <div className="text-center">
              <div className="text-sm text-gray-500 dark:text-zinc-400">
                Loading OAuth configuration...
              </div>
            </div>
          </div>
        ) : (
          <>
            <form onSubmit={(e) => e.preventDefault()} className="flex flex-col">
              <div className="space-y-6 p-6">
                {/* Shared Keys Toggle */}
                {isSharedKeysAvailable && (
                  <div className="flex items-center justify-start gap-2">
                    <Controller
                      name="useSharedKey"
                      control={form.control}
                      render={({ field }) => {
                        return (
                          <Switch
                            checked={field.value}
                            onCheckedChange={(value) => {
                              field.onChange(value);
                            }}
                          />
                        );
                      }}
                    />
                    <span className="text-sm font-medium text-gray-900 dark:text-white">
                      Shared Keys
                    </span>
                  </div>
                )}

                {useSharedKey ? (
                  /* Shared Keys Enabled */
                  <div className="space-y-6">
                    <p className="text-sm text-zinc-500 dark:text-neutral-400">
                      Shared keys are created by the InsForge team for development. It helps you get
                      started, but will show a InsForge logo and name on the OAuth screen.
                    </p>

                    <div className="flex items-center gap-3">
                      <img src={WarningIcon} alt="Warning" className="h-6 w-6" />
                      <span className="text-sm font-medium text-zinc-950 dark:text-white">
                        Shared keys should never be used in production
                      </span>
                    </div>
                  </div>
                ) : (
                  /* Shared Keys Disabled */
                  <div className="space-y-3">
                    <div className="flex items-center gap-2">
                      <ExternalLink className="h-4 w-4 text-blue-600 dark:text-blue-400" />
                      <a
                        href={provider?.setupUrl}
                        target="_blank"
                        rel="noopener noreferrer"
                        className="text-sm text-blue-600 dark:text-blue-400 hover:text-blue-800 font-medium underline"
                      >
                        Create a {provider?.name.split(' ')[0]} OAuth App
                      </a>
                      <span className="text-sm font-normal text-zinc-950 dark:text-white">
                        {' '}
                        and set the callback url to:
                      </span>
                    </div>

                    <div className="space-x-3">
                      <div className="flex items-center gap-2">
                        <code className="flex items-center py-1 px-3 bg-blue-100 dark:bg-neutral-700 text-blue-800 dark:text-blue-300 font-mono break-all rounded-md text-sm">
                          {getCallbackUrl(provider?.id)}
                        </code>
                        <CopyButton text={getCallbackUrl(provider?.id)} />
                      </div>
                    </div>
                  </div>
                )}
              </div>
              {!useSharedKey && (
                <div className="space-y-6 p-6 border-t border-zinc-200 dark:border-neutral-700">
                  <div className="flex flex-row items-center justify-between gap-10">
                    <label className="text-sm text-zinc-950 dark:text-white">Client ID</label>
                    <Input
                      type="text"
                      {...form.register('clientId')}
                      placeholder={`Enter ${provider?.name.split(' ')[0]} OAuth App ID`}
                      className="w-[340px]"
                    />
                  </div>

                  <div className="flex flex-row items-center justify-between gap-10">
                    <label className="text-sm text-zinc-950 dark:text-white">Client Secret</label>
                    <SecretInput
                      {...form.register('clientSecret')}
                      value={clientSecret ?? ''}
                      isVisible={isClientSecretVisible}
                      onToggleVisibility={() => setIsClientSecretVisible((visible) => !visible)}
                      placeholder={`Enter ${provider?.name.split(' ')[0]} OAuth App Secret`}
                      className="w-[340px]"
                    />
                  </div>
                </div>
              )}
            </form>

            <DialogFooter>
              <Button
                type="button"
                className="w-30"
                variant="secondary"
                onClick={onClose}
                disabled={saving}
              >
                Cancel
              </Button>
              <Button type="button" onClick={handleSubmit} disabled={isDisabled()} className="w-30">
                {saving
                  ? mode === 'edit'
                    ? 'Updating...'
                    : 'Adding...'
                  : mode === 'edit'
                    ? 'Update'
                    : 'Add Provider'}
              </Button>
            </DialogFooter>
          </>
        )}
      </DialogContent>
    </Dialog>
  );
}
