"use client";

import { useCallback, useEffect, useState } from "react";

import {
  api,
  type EventType,
  type MessageLogPage,
  type ReminderAudience,
  type SendPreview,
  type SendResult,
  type TemplatePurpose,
} from "@/lib/api/browser";

import { Button, Card, Empty, ErrorNote, Loading, StatusBadge, formatDateTime, inputClass } from "./ui";

/**
 * Send screen and message log (tasks 4.5, 4.6, spec messaging).
 *
 * The send button is deliberately two steps behind a preview. This is the one screen in the
 * application that cannot be undone — a message to 800 people is out the moment it is
 * queued — so the counts and a rendered sample come first, every time.
 */
const EVENTS: { value: EventType; label: string }[] = [
  { value: "mehedi", label: "Mehedi" },
  { value: "marriage", label: "Marriage" },
  { value: "walima", label: "Walima" },
];

const PURPOSES = [
  { value: "invite", label: "Invitation" },
  { value: "reminder_15", label: "Reminder — 15 days" },
  { value: "reminder_7", label: "Reminder — 7 days" },
  { value: "reminder_2", label: "Reminder — 2 days" },
  { value: "thank_you", label: "Thank you" },
] as const;

export default function MessagesView({ canSend }: { canSend: boolean }) {
  return (
    <div className="space-y-4">
      {canSend && <SendPanel />}
      <MessageLog canRetry={canSend} />
    </div>
  );
}

function SendPanel() {
  const [event, setEvent] = useState<EventType>("walima");
  const [audience, setAudience] = useState<ReminderAudience>("all");
  const [purpose, setPurpose] = useState<TemplatePurpose>("invite");
  const [tag, setTag] = useState("");
  const [preview, setPreview] = useState<SendPreview | null>(null);
  const [result, setResult] = useState<SendResult | null>(null);
  const [error, setError] = useState<unknown>(null);
  const [busy, setBusy] = useState(false);

  // Typed from the generated schema, so a renamed enum member fails the build rather
  // than 422-ing at the host mid-send.
  const body = { event, audience, purpose, tag: tag.trim() || null };

  async function runPreview() {
    setBusy(true);
    setError(null);
    setResult(null);
    try {
      setPreview(await api.previewSend(body));
    } catch (err) {
      setError(err);
    } finally {
      setBusy(false);
    }
  }

  async function send() {
    if (!preview) return;
    if (
      !confirm(
        `Queue ${preview.deliverable} message(s) for ${event}? This cannot be recalled once sent.`,
      )
    )
      return;
    setBusy(true);
    setError(null);
    try {
      setResult(await api.send(body));
      setPreview(null);
    } catch (err) {
      setError(err);
    } finally {
      setBusy(false);
    }
  }

  return (
    <Card title="Send">
      <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
        <label className="block">
          <span className="mb-1 block text-xs font-medium text-stone-600">Event</span>
          <select
            value={event}
            onChange={(e) => {
              setEvent(e.target.value as EventType);
              setPreview(null);
            }}
            className={inputClass}
          >
            {EVENTS.map((e) => (
              <option key={e.value} value={e.value}>
                {e.label}
              </option>
            ))}
          </select>
        </label>
        <label className="block">
          <span className="mb-1 block text-xs font-medium text-stone-600">Audience</span>
          <select
            value={audience}
            onChange={(e) => {
              setAudience(e.target.value as ReminderAudience);
              setPreview(null);
            }}
            className={inputClass}
          >
            <option value="all">Everyone invited</option>
            <option value="accepted">Accepted only</option>
            <option value="pending">Not yet responded</option>
          </select>
        </label>
        <label className="block">
          <span className="mb-1 block text-xs font-medium text-stone-600">Template</span>
          <select
            value={purpose}
            onChange={(e) => {
              setPurpose(e.target.value as TemplatePurpose);
              setPreview(null);
            }}
            className={inputClass}
          >
            {PURPOSES.map((p) => (
              <option key={p.value} value={p.value}>
                {p.label}
              </option>
            ))}
          </select>
        </label>
        <label className="block">
          <span className="mb-1 block text-xs font-medium text-stone-600">Tag (optional)</span>
          <input
            value={tag}
            onChange={(e) => {
              setTag(e.target.value);
              setPreview(null);
            }}
            placeholder="e.g. office"
            className={inputClass}
          />
        </label>
      </div>

      <div className="mt-3 flex justify-end">
        <Button variant="secondary" onClick={() => void runPreview()} disabled={busy}>
          {busy && !preview ? "Checking…" : "Preview"}
        </Button>
      </div>

      <ErrorNote error={error} />

      {preview && (
        <div className="mt-4 space-y-3 border-t border-stone-100 pt-4">
          <dl className="grid grid-cols-2 gap-4 sm:grid-cols-4">
            <Stat label="Matched" value={preview.total_matched} />
            <Stat label="Will receive" value={preview.deliverable} tone="good" />
            {/* The gap between matched and deliverable is the whole point of this screen.
                In an email-only v1 these guests need a phone call or a printed card. */}
            <Stat label="No email" value={preview.no_email} tone={preview.no_email ? "warn" : undefined} />
            <Stat label="Opted out" value={preview.opted_out} />
          </dl>

          {preview.missing_placeholders.length > 0 && (
            <p role="alert" className="rounded-lg bg-amber-50 px-3 py-2 text-sm text-amber-900">
              Unresolved placeholders: {preview.missing_placeholders.join(", ")}. They will
              appear literally in the message.
            </p>
          )}

          <div className="rounded-lg border border-stone-200 bg-stone-50 p-3">
            <p className="text-xs font-medium text-stone-500">Sample — first recipient</p>
            <p className="mt-1 font-medium">{preview.sample_subject ?? "(no subject)"}</p>
            <pre className="mt-2 whitespace-pre-wrap break-words font-sans text-sm text-stone-700">
              {preview.sample_body ?? "(no body)"}
            </pre>
          </div>

          <div className="flex justify-end">
            <Button onClick={() => void send()} disabled={busy || preview.deliverable === 0}>
              {busy ? "Queueing…" : `Send to ${preview.deliverable}`}
            </Button>
          </div>
        </div>
      )}

      {result && (
        <p className="mt-4 rounded-lg bg-emerald-50 px-3 py-2 text-sm text-emerald-900">
          Queued {result.queued}. Skipped {result.skipped_no_email} without an email
          {result.already_queued > 0 && `, ${result.already_queued} were already queued`}.
        </p>
      )}
    </Card>
  );
}

function MessageLog({ canRetry }: { canRetry: boolean }) {
  const [filter, setFilter] = useState("");
  const [page, setPage] = useState(1);
  const [data, setData] = useState<MessageLogPage | null>(null);
  const [error, setError] = useState<unknown>(null);

  const load = useCallback(async () => {
    const params = new URLSearchParams({ page: String(page), page_size: "50" });
    if (filter) params.set("job_status", filter);
    try {
      setData(await api.messages(params));
      setError(null);
    } catch (err) {
      setError(err);
    }
  }, [filter, page]);

  useEffect(() => {
    void load();
  }, [load]);

  const failed = data?.counts_by_status?.failed ?? 0;

  return (
    <Card
      title="Message log"
      actions={
        canRetry &&
        failed > 0 && (
          <Button
            variant="secondary"
            onClick={async () => {
              await api.retryFailed();
              await load();
            }}
          >
            Retry {failed} failed
          </Button>
        )
      }
    >
      <div className="mb-3 flex flex-wrap items-center gap-2">
        <select
          value={filter}
          onChange={(e) => {
            setFilter(e.target.value);
            setPage(1);
          }}
          aria-label="Filter by status"
          className={`${inputClass} max-w-[10rem]`}
        >
          <option value="">All statuses</option>
          {["queued", "sending", "sent", "delivered", "failed", "skipped"].map((s) => (
            <option key={s} value={s}>
              {s}
            </option>
          ))}
        </select>
        {data &&
          Object.entries(data.counts_by_status).map(([status, count]) => (
            <span key={status} className="text-xs text-stone-500">
              {status}: <strong className="text-stone-700">{String(count)}</strong>
            </span>
          ))}
      </div>

      <ErrorNote error={error} />

      {!data ? (
        <Loading />
      ) : data.items.length === 0 ? (
        <Empty>No messages yet.</Empty>
      ) : (
        <div className="overflow-x-auto">
          <table className="w-full min-w-[42rem] text-left text-sm">
            <thead>
              <tr className="border-b border-stone-200 text-xs uppercase tracking-wide text-stone-500">
                <th scope="col" className="py-2 pr-3 font-medium">Status</th>
                <th scope="col" className="py-2 pr-3 font-medium">Scheduled</th>
                <th scope="col" className="py-2 pr-3 font-medium">Sent</th>
                <th scope="col" className="py-2 pr-3 font-medium">Attempts</th>
                <th scope="col" className="py-2 pr-3 font-medium">Detail</th>
              </tr>
            </thead>
            <tbody>
              {data.items.map((job) => (
                <tr key={job.id} className="border-b border-stone-100 last:border-0">
                  <td className="py-2 pr-3">
                    <StatusBadge status={job.status} />
                  </td>
                  <td className="py-2 pr-3 whitespace-nowrap text-stone-600">
                    {formatDateTime(job.scheduled_for)}
                  </td>
                  <td className="py-2 pr-3 whitespace-nowrap text-stone-600">
                    {job.sent_at ? formatDateTime(job.sent_at) : "—"}
                  </td>
                  <td className="py-2 pr-3 text-stone-600">{job.attempts}</td>
                  <td className="py-2 pr-3 text-xs text-stone-500">
                    {job.error_message ?? job.skip_reason ?? job.provider_message_id ?? "—"}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      {data && data.total > 50 && (
        <nav aria-label="Pagination" className="mt-4 flex items-center justify-between text-sm">
          <Button variant="secondary" disabled={page <= 1} onClick={() => setPage((p) => p - 1)}>
            Previous
          </Button>
          <span className="text-stone-500">
            {data.items.length} of {data.total}
          </span>
          <Button
            variant="secondary"
            disabled={page * 50 >= data.total}
            onClick={() => setPage((p) => p + 1)}
          >
            Next
          </Button>
        </nav>
      )}
    </Card>
  );
}

function Stat({
  label,
  value,
  tone,
}: {
  label: string;
  value: number;
  tone?: "good" | "warn";
}) {
  const color =
    tone === "good" ? "text-emerald-700" : tone === "warn" ? "text-amber-700" : "text-stone-900";
  return (
    <div>
      <dd className={`text-2xl font-semibold ${color}`}>{value}</dd>
      <dt className="text-xs text-stone-500">{label}</dt>
    </div>
  );
}
