'use client';

/**
 * Sales send-from config card (Phase 7 §5.9).
 *
 * Lives on /[portSlug]/admin/email below the existing noreply transport
 * card. Lets per-port admins configure the SMTP/IMAP creds + body templates
 * that the document-sends flow uses.
 *
 * §14.10 enforcement: passwords are write-only. The GET endpoint never
 * returns the decrypted value - only a `*PassIsSet` boolean. Empty
 * password input means "leave unchanged"; explicit `null` sent over the
 * wire means "clear".
 */
import { useEffect, useState } from 'react';
import { CheckCircle2, Loader2, XCircle } 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 { Switch } from '@/components/ui/switch';
import { Textarea } from '@/components/ui/textarea';
import { apiFetch } from '@/lib/api/client';
import { TemplateTokenPicker } from '@/components/admin/shared/template-token-picker';
import { toastError } from '@/lib/api/toast-error';

interface SalesConfigResponse {
  data: {
    email: {
      fromAddress: string;
      smtpHost: string | null;
      smtpPort: number;
      smtpSecure: boolean;
      smtpUser: string | null;
      authMethod: string;
      smtpPassIsSet: boolean;
      isUsable: boolean;
    };
    imap: {
      imapHost: string | null;
      imapPort: number;
      imapUser: string | null;
      imapPassIsSet: boolean;
      isUsable: boolean;
    };
    content: {
      noreplyFromAddress: string;
      templateBerthPdfBody: string;
      templateBrochureBody: string;
      brochureMaxUploadMb: number;
      emailAttachThresholdMb: number;
    };
  };
}

interface FormState {
  fromAddress: string;
  smtpHost: string;
  smtpPort: number | '';
  smtpSecure: boolean;
  smtpUser: string;
  smtpPass: string; // empty = unchanged
  imapHost: string;
  imapPort: number | '';
  imapUser: string;
  imapPass: string;
  noreplyFromAddress: string;
  templateBerthPdfBody: string;
  templateBrochureBody: string;
  brochureMaxUploadMb: number | '';
  emailAttachThresholdMb: number | '';
}

const EMPTY_FORM: FormState = {
  fromAddress: '',
  smtpHost: '',
  smtpPort: 587,
  smtpSecure: false,
  smtpUser: '',
  smtpPass: '',
  imapHost: '',
  imapPort: 993,
  imapUser: '',
  imapPass: '',
  noreplyFromAddress: '',
  templateBerthPdfBody: '',
  templateBrochureBody: '',
  brochureMaxUploadMb: 50,
  emailAttachThresholdMb: 15,
};

export function SalesEmailConfigCard() {
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [testing, setTesting] = useState(false);
  const [lastTest, setLastTest] = useState<{ ok: boolean; message: string; at: Date } | null>(null);
  const [smtpPassSet, setSmtpPassSet] = useState(false);
  const [imapPassSet, setImapPassSet] = useState(false);
  const [form, setForm] = useState<FormState>(EMPTY_FORM);

  async function refresh() {
    setLoading(true);
    try {
      const res: SalesConfigResponse = await apiFetch('/api/v1/admin/email/sales-config');
      setSmtpPassSet(res.data.email.smtpPassIsSet);
      setImapPassSet(res.data.imap.imapPassIsSet);
      setForm({
        fromAddress: res.data.email.fromAddress,
        smtpHost: res.data.email.smtpHost ?? '',
        smtpPort: res.data.email.smtpPort,
        smtpSecure: res.data.email.smtpSecure,
        smtpUser: res.data.email.smtpUser ?? '',
        smtpPass: '',
        imapHost: res.data.imap.imapHost ?? '',
        imapPort: res.data.imap.imapPort,
        imapUser: res.data.imap.imapUser ?? '',
        imapPass: '',
        noreplyFromAddress: res.data.content.noreplyFromAddress,
        templateBerthPdfBody: res.data.content.templateBerthPdfBody,
        templateBrochureBody: res.data.content.templateBrochureBody,
        brochureMaxUploadMb: res.data.content.brochureMaxUploadMb,
        emailAttachThresholdMb: res.data.content.emailAttachThresholdMb,
      });
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    // Initial load on mount - canonical fetch-once pattern.
    // eslint-disable-next-line react-hooks/set-state-in-effect
    void refresh();
  }, []);

  function update<K extends keyof FormState>(key: K, value: FormState[K]) {
    setForm((prev) => ({ ...prev, [key]: value }));
  }

  async function handleTestSmtp() {
    setTesting(true);
    setLastTest(null);
    try {
      const res = (await apiFetch('/api/v1/admin/email/sales-config/test-smtp', {
        method: 'POST',
        body: {},
      })) as { data: { ok: boolean; to?: string; error?: string } };
      if (res.data.ok) {
        setLastTest({
          ok: true,
          message: `Test email sent to ${res.data.to ?? 'your inbox'}. Check delivery.`,
          at: new Date(),
        });
        toast.success('Test SMTP send queued.');
      } else {
        setLastTest({
          ok: false,
          message: res.data.error ?? 'Unknown error',
          at: new Date(),
        });
        toast.error('SMTP test failed  -  see card for details.');
      }
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      setLastTest({ ok: false, message: msg, at: new Date() });
      toastError(err);
    } finally {
      setTesting(false);
    }
  }

  async function handleSave() {
    setSaving(true);
    try {
      const payload: Record<string, unknown> = {
        fromAddress: form.fromAddress || null,
        smtpHost: form.smtpHost || null,
        smtpPort: typeof form.smtpPort === 'number' ? form.smtpPort : null,
        smtpSecure: form.smtpSecure,
        smtpUser: form.smtpUser || null,
        imapHost: form.imapHost || null,
        imapPort: typeof form.imapPort === 'number' ? form.imapPort : null,
        imapUser: form.imapUser || null,
        noreplyFromAddress: form.noreplyFromAddress || null,
        templateBerthPdfBody: form.templateBerthPdfBody,
        templateBrochureBody: form.templateBrochureBody,
        brochureMaxUploadMb:
          typeof form.brochureMaxUploadMb === 'number' ? form.brochureMaxUploadMb : null,
        emailAttachThresholdMb:
          typeof form.emailAttachThresholdMb === 'number' ? form.emailAttachThresholdMb : null,
      };
      // Only send password fields when the user actually typed something.
      if (form.smtpPass !== '') payload.smtpPass = form.smtpPass;
      if (form.imapPass !== '') payload.imapPass = form.imapPass;

      await apiFetch('/api/v1/admin/email/sales-config', { method: 'PATCH', body: payload });
      toast.success('Sales email settings saved');
      await refresh();
    } catch (err) {
      toastError(err);
    } finally {
      setSaving(false);
    }
  }

  if (loading) {
    return (
      <Card>
        <CardContent className="flex items-center gap-2 py-6 text-sm text-muted-foreground">
          <Loader2 className="h-4 w-4 animate-spin" aria-hidden /> Loading sales email config…
        </CardContent>
      </Card>
    );
  }

  return (
    <div className="space-y-4">
      <Card>
        <CardHeader>
          <CardTitle>Sales send-from account</CardTitle>
          <CardDescription>
            SMTP credentials for human-touch outbound (brochures + per-berth PDFs). IMAP creds
            enable the bounce monitor - leave blank to disable bounce-rejection banners. Passwords
            are encrypted at rest and never returned by the API.
          </CardDescription>
        </CardHeader>
        <CardContent className="space-y-4">
          <div className="grid gap-3 md:grid-cols-2">
            <Field label="From address" id="sef-from">
              <Input
                id="sef-from"
                type="email"
                value={form.fromAddress}
                onChange={(e) => update('fromAddress', e.target.value)}
                placeholder="sales@portnimara.com"
              />
            </Field>
            <Field label="SMTP host" id="sef-smtp-host">
              <Input
                id="sef-smtp-host"
                value={form.smtpHost}
                onChange={(e) => update('smtpHost', e.target.value)}
                placeholder="smtp.gmail.com"
              />
            </Field>
            <Field label="SMTP port" id="sef-smtp-port">
              <Input
                id="sef-smtp-port"
                type="number"
                value={form.smtpPort}
                onChange={(e) =>
                  update('smtpPort', e.target.value === '' ? '' : Number(e.target.value))
                }
              />
            </Field>
            <div className="flex items-end justify-between gap-2">
              <Label htmlFor="sef-smtp-secure" className="text-sm">
                SSL (true=465, false=STARTTLS on 587)
              </Label>
              <Switch
                id="sef-smtp-secure"
                checked={form.smtpSecure}
                onCheckedChange={(v) => update('smtpSecure', v)}
              />
            </div>
            <Field label="SMTP username" id="sef-smtp-user">
              <Input
                id="sef-smtp-user"
                value={form.smtpUser}
                onChange={(e) => update('smtpUser', e.target.value)}
              />
            </Field>
            <Field
              label={`SMTP password ${smtpPassSet ? '(stored  -  leave blank to keep)' : ''}`}
              id="sef-smtp-pass"
            >
              <Input
                id="sef-smtp-pass"
                type="password"
                value={form.smtpPass}
                onChange={(e) => update('smtpPass', e.target.value)}
                placeholder={smtpPassSet ? '••••••••' : 'app password'}
              />
            </Field>
          </div>
        </CardContent>
      </Card>

      <Card>
        <CardHeader>
          <CardTitle>Bounce monitor (IMAP)</CardTitle>
          <CardDescription>
            Required only for the async-bounce banner (§14.9). Same provider account as SMTP in most
            setups.
          </CardDescription>
        </CardHeader>
        <CardContent className="grid gap-3 md:grid-cols-2">
          <Field label="IMAP host" id="sef-imap-host">
            <Input
              id="sef-imap-host"
              value={form.imapHost}
              onChange={(e) => update('imapHost', e.target.value)}
              placeholder="imap.gmail.com"
            />
          </Field>
          <Field label="IMAP port" id="sef-imap-port">
            <Input
              id="sef-imap-port"
              type="number"
              value={form.imapPort}
              onChange={(e) =>
                update('imapPort', e.target.value === '' ? '' : Number(e.target.value))
              }
            />
          </Field>
          <Field label="IMAP username" id="sef-imap-user">
            <Input
              id="sef-imap-user"
              value={form.imapUser}
              onChange={(e) => update('imapUser', e.target.value)}
            />
          </Field>
          <Field
            label={`IMAP password ${imapPassSet ? '(stored  -  leave blank to keep)' : ''}`}
            id="sef-imap-pass"
          >
            <Input
              id="sef-imap-pass"
              type="password"
              value={form.imapPass}
              onChange={(e) => update('imapPass', e.target.value)}
              placeholder={imapPassSet ? '••••••••' : 'app password'}
            />
          </Field>
        </CardContent>
      </Card>

      <Card>
        <CardHeader>
          <CardTitle>Body templates</CardTitle>
          <CardDescription>
            Default markdown bodies used when a rep doesn&rsquo;t write a custom one. Tokens like{' '}
            <code>{'{{client.fullName}}'}</code> are expanded server-side.
          </CardDescription>
        </CardHeader>
        <CardContent className="space-y-4">
          <details className="rounded-md border bg-muted/30 px-3 py-2 text-xs">
            <summary className="cursor-pointer font-medium text-foreground">
              Available tokens
            </summary>
            <div className="mt-3">
              <TemplateTokenPicker />
            </div>
          </details>
          <Field
            label="Berth PDF body"
            id="sef-tmpl-berth"
            help="Sent when a rep emails a berth's PDF spec to a prospect. Markdown supported."
          >
            <Textarea
              id="sef-tmpl-berth"
              rows={6}
              value={form.templateBerthPdfBody}
              onChange={(e) => update('templateBerthPdfBody', e.target.value)}
              className="font-mono text-sm"
            />
          </Field>
          <Field
            label="Brochure body"
            id="sef-tmpl-broc"
            help="Sent when a rep emails the port's master brochure to a prospect."
          >
            <Textarea
              id="sef-tmpl-broc"
              rows={6}
              value={form.templateBrochureBody}
              onChange={(e) => update('templateBrochureBody', e.target.value)}
              className="font-mono text-sm"
            />
          </Field>
          <div className="grid gap-3 md:grid-cols-2">
            <Field label="Brochure max upload (MB)" id="sef-broc-max">
              <Input
                id="sef-broc-max"
                type="number"
                value={form.brochureMaxUploadMb}
                onChange={(e) =>
                  update('brochureMaxUploadMb', e.target.value === '' ? '' : Number(e.target.value))
                }
              />
            </Field>
            <Field
              label="Attach-vs-link threshold (MB)"
              id="sef-attach"
              help="Files smaller than this go in the email as an attachment. Larger files send a 24-hour signed download link instead so the message stays under SMTP size limits and doesn't bounce. Default 15 MB."
            >
              <Input
                id="sef-attach"
                type="number"
                value={form.emailAttachThresholdMb}
                onChange={(e) =>
                  update(
                    'emailAttachThresholdMb',
                    e.target.value === '' ? '' : Number(e.target.value),
                  )
                }
              />
            </Field>
          </div>
          <Field label="Noreply from address" id="sef-noreply">
            <Input
              id="sef-noreply"
              type="email"
              value={form.noreplyFromAddress}
              onChange={(e) => update('noreplyFromAddress', e.target.value)}
            />
          </Field>
        </CardContent>
      </Card>

      {lastTest ? (
        <div
          className={`flex items-start gap-2 rounded-md border p-3 text-sm ${
            lastTest.ok
              ? 'border-emerald-200 bg-emerald-50 text-emerald-900'
              : 'border-rose-200 bg-rose-50 text-rose-900'
          }`}
        >
          {lastTest.ok ? (
            <CheckCircle2 className="mt-0.5 h-4 w-4 shrink-0" aria-hidden />
          ) : (
            <XCircle className="mt-0.5 h-4 w-4 shrink-0" aria-hidden />
          )}
          <div className="flex-1">
            <p className="font-medium">{lastTest.ok ? 'SMTP test sent' : 'SMTP test failed'}</p>
            <p className="text-xs">{lastTest.message}</p>
            <p className="mt-0.5 text-xs opacity-70">{lastTest.at.toLocaleTimeString()}</p>
          </div>
        </div>
      ) : null}

      <div className="flex flex-wrap items-center justify-end gap-2">
        <Button
          variant="outline"
          onClick={handleTestSmtp}
          disabled={testing || saving}
          title="Send a test message to your account via the configured SMTP credentials."
        >
          {testing ? <Loader2 className="mr-2 h-4 w-4 animate-spin" aria-hidden /> : null}
          Test SMTP
        </Button>
        <Button onClick={handleSave} disabled={saving}>
          {saving && <Loader2 className="mr-2 h-4 w-4 animate-spin" aria-hidden />}
          Save sales email settings
        </Button>
      </div>
    </div>
  );
}

function Field({
  label,
  id,
  children,
  help,
}: {
  label: string;
  id: string;
  children: React.ReactNode;
  /** Plain-text caption rendered below the label. Use for any setting
   *  whose meaning isn't immediately obvious from the label alone. */
  help?: string;
}) {
  return (
    <div className="space-y-1">
      <Label htmlFor={id}>{label}</Label>
      {help && <p className="text-xs text-muted-foreground">{help}</p>}
      {children}
    </div>
  );
}
