import { RECIPIENT_ROLES_DESCRIPTION } from '@documenso/lib/constants/recipient-roles';
import type { TDetectedRecipientSchema } from '@documenso/lib/server-only/ai/envelope/detect-recipients/schema';
import { Alert, AlertDescription } from '@documenso/ui/primitives/alert';
import { AvatarWithText } from '@documenso/ui/primitives/avatar';
import { Button } from '@documenso/ui/primitives/button';
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@documenso/ui/primitives/dialog';
import { msg } from '@lingui/core/macro';
import { useLingui } from '@lingui/react';
import { Plural, Trans } from '@lingui/react/macro';
import { CheckIcon, ShieldCheckIcon, UserIcon, XIcon } from 'lucide-react';
import { useCallback, useEffect, useState } from 'react';

import {
  AiApiError,
  type DetectRecipientsProgressEvent,
  detectRecipients,
} from '../../../server/api/ai/detect-recipients.client';
import { AnimatedDocumentScanner } from '../general/animated-document-scanner';

type DialogState = 'PROMPT' | 'PROCESSING' | 'REVIEW' | 'ERROR' | 'RATE_LIMITED';

type AiRecipientDetectionDialogProps = {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  onComplete: (recipients: TDetectedRecipientSchema[]) => void;
  envelopeId: string;
  teamId: number;
};

const PROCESSING_MESSAGES = [
  msg`Reading your document`,
  msg`Analyzing pages`,
  msg`Looking for signature fields`,
  msg`Identifying recipients`,
  msg`Extracting contact details`,
  msg`Almost done`,
] as const;

export const AiRecipientDetectionDialog = ({
  open,
  onOpenChange,
  onComplete,
  envelopeId,
  teamId,
}: AiRecipientDetectionDialogProps) => {
  const { _ } = useLingui();

  const [state, setState] = useState<DialogState>('PROMPT');
  const [messageIndex, setMessageIndex] = useState(0);
  const [detectedRecipients, setDetectedRecipients] = useState<TDetectedRecipientSchema[]>([]);
  const [error, setError] = useState<string | null>(null);
  const [progress, setProgress] = useState<DetectRecipientsProgressEvent | null>(null);

  const onDetectClick = useCallback(async () => {
    setState('PROCESSING');
    setMessageIndex(0);
    setError(null);
    setProgress(null);

    try {
      await detectRecipients({
        request: {
          envelopeId,
          teamId,
        },
        onProgress: (progressEvent) => {
          setProgress(progressEvent);
        },
        onComplete: (event) => {
          setDetectedRecipients(event.recipients);
          setState('REVIEW');
        },
        onError: (err) => {
          console.error('Detection failed:', err);

          if (err.status === 429) {
            setState('RATE_LIMITED');
            return;
          }

          setError(err.message);
          setState('ERROR');
        },
      });
    } catch (err) {
      console.error('Detection failed:', err);

      if (err instanceof AiApiError && err.status === 429) {
        setState('RATE_LIMITED');
        return;
      }

      setError(err instanceof Error ? err.message : 'Failed to detect recipients');
      setState('ERROR');
    }
  }, [envelopeId, teamId]);

  const handleRemoveRecipient = (index: number) => {
    setDetectedRecipients((prev) => prev.filter((_, i) => i !== index));
  };

  const onAddRecipients = () => {
    onComplete(detectedRecipients);
    onOpenChange(false);
    setState('PROMPT');
    setDetectedRecipients([]);
  };

  const onClose = () => {
    onOpenChange(false);
    setState('PROMPT');
    setDetectedRecipients([]);
    setError(null);
    setProgress(null);
  };

  useEffect(() => {
    if (state !== 'PROCESSING') {
      return;
    }

    const interval = setInterval(() => {
      setMessageIndex((prev) => (prev + 1) % PROCESSING_MESSAGES.length);
    }, 4000);

    return () => clearInterval(interval);
  }, [state]);

  return (
    <Dialog open={open}>
      <DialogContent className="sm:max-w-lg" hideClose={true}>
        {state === 'PROMPT' && (
          <>
            <DialogHeader>
              <DialogTitle>
                <Trans>Detect recipients</Trans>
              </DialogTitle>
            </DialogHeader>

            <div>
              <p className="text-muted-foreground text-sm">
                <Trans>
                  We'll scan your document to find signature fields and identify who needs to sign. Detected recipients
                  will be suggested for you to review.
                </Trans>
              </p>

              <Alert className="mt-4 flex items-center gap-2 space-y-0" variant="neutral">
                <ShieldCheckIcon className="h-5 w-5 stroke-green-600" />
                <AlertDescription className="mt-0">
                  <Trans>Your document is processed securely using AI services that don't retain your data.</Trans>
                </AlertDescription>
              </Alert>
            </div>

            <DialogFooter>
              <Button type="button" variant="ghost" onClick={onClose}>
                <Trans>Skip</Trans>
              </Button>
              <Button type="button" onClick={onDetectClick}>
                <Trans>Detect</Trans>
              </Button>
            </DialogFooter>
          </>
        )}

        {state === 'PROCESSING' && (
          <>
            <DialogHeader>
              <DialogTitle>
                <Trans>Detecting recipients</Trans>
              </DialogTitle>
            </DialogHeader>

            <div className="flex flex-col items-center py-8">
              <AnimatedDocumentScanner />

              <p className="mt-8 text-muted-foreground">{_(PROCESSING_MESSAGES[messageIndex])}</p>

              {progress && (
                <p className="mt-2 text-muted-foreground/60 text-xs">
                  <Plural
                    value={progress.recipientsDetected}
                    one={
                      <Trans>
                        Page {progress.pagesProcessed} of {progress.totalPages} - # recipient found
                      </Trans>
                    }
                    other={
                      <Trans>
                        Page {progress.pagesProcessed} of {progress.totalPages} - # recipients found
                      </Trans>
                    }
                  />
                </p>
              )}

              <p className="mt-2 max-w-[40ch] text-center text-muted-foreground/60 text-xs">
                <Trans>This can take a minute or two depending on the size of your document.</Trans>
              </p>

              <div className="mt-4 flex gap-1">
                {PROCESSING_MESSAGES.map((_, index) => (
                  <div
                    key={index}
                    className={`h-1.5 w-1.5 rounded-full transition-all duration-300 ${
                      index === messageIndex ? 'w-4 bg-primary' : 'bg-muted-foreground/30'
                    }`}
                  />
                ))}
              </div>
            </div>
          </>
        )}

        {state === 'REVIEW' && (
          <>
            <DialogHeader>
              <DialogTitle>
                <Trans>Detected recipients</Trans>
              </DialogTitle>
            </DialogHeader>

            <div className="max-h-[400px] overflow-y-auto">
              {detectedRecipients.length === 0 ? (
                <div className="flex flex-col items-center py-8">
                  <UserIcon className="h-12 w-12 text-muted-foreground/50" />
                  <p className="mt-4 text-center text-muted-foreground text-sm">
                    <Trans>No recipients were detected in your document.</Trans>
                  </p>
                  <p className="mt-1 text-center text-muted-foreground/70 text-xs">
                    <Trans>You can add recipients manually in the editor.</Trans>
                  </p>
                </div>
              ) : (
                <>
                  <p className="text-muted-foreground text-sm">
                    <Plural
                      value={detectedRecipients.length}
                      one="We found # recipient in your document."
                      other="We found # recipients in your document."
                    />
                  </p>

                  <ul className="mt-4 divide-y rounded-lg border">
                    {detectedRecipients.map((recipient, index) => (
                      <li key={index} className="flex items-center justify-between px-4 py-3">
                        <AvatarWithText
                          avatarFallback={
                            recipient.name
                              ? recipient.name.slice(0, 1).toUpperCase()
                              : recipient.email
                                ? recipient.email.slice(0, 1).toUpperCase()
                                : '?'
                          }
                          primaryText={
                            <p className="font-medium text-foreground text-sm">
                              {recipient.name || _(msg`Unknown name`)}
                            </p>
                          }
                          secondaryText={
                            <div className="text-muted-foreground text-xs">
                              <p className="text-muted-foreground/70 italic">
                                {recipient.email || _(msg`No email detected`)}
                              </p>
                              <p>{_(RECIPIENT_ROLES_DESCRIPTION[recipient.role].roleName)}</p>
                            </div>
                          }
                        />

                        <button
                          type="button"
                          className="h-8 w-8 p-0 text-muted-foreground/80 hover:text-destructive focus-visible:border-destructive focus-visible:ring-destructive"
                          onClick={() => handleRemoveRecipient(index)}
                        >
                          <span className="sr-only">
                            <Trans>Remove recipient</Trans>
                          </span>

                          <XIcon className="h-4 w-4" aria-hidden="true" />
                        </button>
                      </li>
                    ))}
                  </ul>
                </>
              )}
            </div>

            <DialogFooter>
              <Button type="button" variant="ghost" onClick={onClose}>
                <Trans>Cancel</Trans>
              </Button>

              {detectedRecipients.length > 0 && (
                <Button type="button" onClick={onAddRecipients}>
                  <CheckIcon className="mr-2 -ml-1 h-4 w-4" />
                  <Trans>Add recipients</Trans>
                </Button>
              )}
            </DialogFooter>
          </>
        )}

        {state === 'ERROR' && (
          <>
            <DialogHeader>
              <DialogTitle>
                <Trans>Detection failed</Trans>
              </DialogTitle>
            </DialogHeader>

            <div className="py-4">
              <p className="text-muted-foreground text-sm">
                <Trans>Something went wrong while detecting recipients.</Trans>
              </p>

              {error && <p className="mt-2 text-destructive text-sm">{error}</p>}
            </div>

            <DialogFooter>
              <Button type="button" variant="ghost" onClick={onClose}>
                <Trans>Close</Trans>
              </Button>

              <Button type="button" onClick={onDetectClick}>
                <Trans>Try again</Trans>
              </Button>
            </DialogFooter>
          </>
        )}

        {state === 'RATE_LIMITED' && (
          <>
            <DialogHeader>
              <DialogTitle>
                <Trans>Too many requests</Trans>
              </DialogTitle>
            </DialogHeader>

            <div className="py-4">
              <p className="text-muted-foreground text-sm">
                <Trans>You've made too many detection requests. Please wait a minute before trying again.</Trans>
              </p>
            </div>

            <DialogFooter>
              <Button type="button" variant="ghost" onClick={onClose}>
                <Trans>Close</Trans>
              </Button>
              <Button type="button" onClick={onDetectClick}>
                <Trans>Try again</Trans>
              </Button>
            </DialogFooter>
          </>
        )}
      </DialogContent>
    </Dialog>
  );
};
