'use client';

import { useCallback, useEffect, useState } from 'react';
import Link from 'next/link';
import { useParams } from 'next/navigation';
import type { Route } from 'next';
import { ArrowRight, Eye, RefreshCw, Send } from 'lucide-react';
import { toast } from 'sonner';

import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { apiFetch } from '@/lib/api/client';

interface PreviewResponse {
  data: { subject: string; html: string };
}

interface TemplateRegistryResponse {
  data: Array<{ id: string; label: string; description: string }>;
}

// Sentinel value for the Generic preview option. Select forbids empty-string
// values, so we use a literal that the GET handler doesn't recognise as a
// templateId and falls through to the generic sample.
const GENERIC_VALUE = '__generic__';

/**
 * Live preview of the branded transactional email shell plus a
 * "send a test" affordance. Both use the current port's branding so
 * admins can sanity-check uploads + colour + header/footer HTML
 * without firing one of the real flows.
 */
export function EmailPreviewCard() {
  const params = useParams<{ portSlug: string }>();
  const portSlug = params?.portSlug ?? '';
  const [html, setHtml] = useState<string | null>(null);
  const [subject, setSubject] = useState<string | null>(null);
  const [loadingPreview, setLoadingPreview] = useState(false);
  const [testEmail, setTestEmail] = useState('');
  const [sending, setSending] = useState(false);
  const [templates, setTemplates] = useState<TemplateRegistryResponse['data']>([]);
  const [templateId, setTemplateId] = useState<string>(GENERIC_VALUE);

  // Pull the registry once on mount so the dropdown reflects every
  // transactional template the system can emit. The same list backs the
  // per-template tester on /admin/email - this card surfaces it inline
  // with the branding controls so the visual feedback loop is tight.
  useEffect(() => {
    apiFetch<TemplateRegistryResponse>('/api/v1/admin/email/test-template')
      .then((res) => setTemplates(res.data))
      .catch(() => {
        /* non-fatal - the generic preview still works without the registry */
      });
  }, []);

  const refreshPreview = useCallback(
    async (id: string = templateId) => {
      setLoadingPreview(true);
      try {
        const qs = id === GENERIC_VALUE ? '' : `?templateId=${encodeURIComponent(id)}`;
        const res = await apiFetch<PreviewResponse>(`/api/v1/admin/branding/email-preview${qs}`);
        setSubject(res.data.subject);
        setHtml(res.data.html);
      } catch (err: unknown) {
        toast.error(err instanceof Error ? err.message : 'Preview failed');
      } finally {
        setLoadingPreview(false);
      }
    },
    [templateId],
  );

  function onTemplateChange(next: string) {
    setTemplateId(next);
    // Auto-refresh when the user picks a different template so they don't
    // have to chase a separate "Refresh" click for every selection. Save +
    // re-render of branding fields still requires the visible Refresh
    // button (we can't auto-detect a save).
    void refreshPreview(next);
  }

  async function sendTest() {
    if (!testEmail) return;
    setSending(true);
    try {
      await apiFetch('/api/v1/admin/branding/email-preview', {
        method: 'POST',
        body: {
          recipient: testEmail,
          templateId: templateId === GENERIC_VALUE ? null : templateId,
        },
      });
      toast.success(`Test email queued to ${testEmail}`);
    } catch (err: unknown) {
      toast.error(err instanceof Error ? err.message : 'Send failed');
    } finally {
      setSending(false);
    }
  }

  return (
    <Card>
      <CardHeader>
        <div className="flex items-start justify-between gap-3">
          <div>
            <CardTitle>Preview & test</CardTitle>
            <CardDescription>
              Renders a sample transactional email with the current port&apos;s branding. Switch
              templates to see how each one looks. Save branding changes first, then click Refresh
              to pick up the new logo / colour / background.
            </CardDescription>
          </div>
          <Button
            variant="outline"
            size="sm"
            onClick={() => refreshPreview()}
            disabled={loadingPreview}
          >
            {html ? (
              <RefreshCw className="mr-1.5 h-4 w-4" aria-hidden />
            ) : (
              <Eye className="mr-1.5 h-4 w-4" aria-hidden />
            )}
            {loadingPreview ? 'Loading…' : html ? 'Refresh' : 'Show preview'}
          </Button>
        </div>
      </CardHeader>
      <CardContent className="space-y-4">
        <div className="flex flex-wrap items-center gap-2">
          <Label htmlFor="template-select" className="text-xs font-medium text-muted-foreground">
            Template
          </Label>
          <Select value={templateId} onValueChange={onTemplateChange}>
            <SelectTrigger id="template-select" className="w-full sm:w-[320px]">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value={GENERIC_VALUE}>Generic sample (branding only)</SelectItem>
              {templates.map((t) => (
                <SelectItem key={t.id} value={t.id}>
                  {t.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
        {html ? (
          <div className="space-y-2">
            <div className="text-xs text-muted-foreground">
              Subject: <span className="font-medium text-foreground">{subject}</span>
            </div>
            <div className="rounded-md border bg-white">
              {/* Sandboxed so the rendered HTML can't execute scripts or
                  steal the admin's session. Same-origin would let it call
                  /api/* with the admin's cookies. */}
              <iframe
                title="Email preview"
                srcDoc={html}
                sandbox=""
                className="h-[640px] w-full rounded-md"
              />
            </div>
          </div>
        ) : (
          <p className="text-sm text-muted-foreground">
            Click <span className="font-medium">Show preview</span> to render a sample email.
          </p>
        )}
        <div className="space-y-2 border-t pt-4">
          <Label htmlFor="test-email-input">Send a test</Label>
          <div className="flex flex-wrap items-center gap-2">
            <Input
              id="test-email-input"
              type="email"
              value={testEmail}
              onChange={(e) => setTestEmail(e.target.value)}
              placeholder="you@example.com"
              className="flex-1 min-w-[240px]"
            />
            <Button onClick={sendTest} disabled={sending || !testEmail}>
              <Send className="mr-1.5 h-4 w-4" />
              {sending ? 'Sending…' : 'Send test email'}
            </Button>
          </div>
          <p className="text-xs text-muted-foreground">
            Sends the same sample email to the address you enter. Useful for checking how it lands
            in Gmail, Outlook, Apple Mail, etc.
          </p>
          {/* The branded shell only fires the generic sample copy. To
              test the actual subject/body of a specific transactional
              template (password reset, EOI invite, signing reminder
              etc.), use the per-template tester on Email Settings. */}
          {portSlug ? (
            <Link
              href={`/${portSlug}/admin/email` as Route}
              className="inline-flex items-center gap-1 text-xs font-medium text-primary hover:underline"
            >
              Test individual templates (password reset, EOI invite, signing reminder, …)
              <ArrowRight className="h-3 w-3" aria-hidden />
            </Link>
          ) : null}
        </div>
      </CardContent>
    </Card>
  );
}
