"use client";

import { useCallback, useEffect, useState } from "react";
import { ArrowDown, ArrowUp, GripVertical, Pencil, Plus, RefreshCw, Search, Trash2 } from "lucide-react";
import { toast } from "react-hot-toast";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { ConfirmContentDeleteDialog } from "./confirm-content-delete-dialog";
import { MarkdownPreview } from "./content-fields";
import { FaqEditorDialog } from "./faq-editor-dialog";
import { moveFaqOrder } from "./content-contract";
import { createFaq, deleteFaq, fetchCmsChannels, fetchFaqs, reorderFaqs, updateFaq } from "./client-api";
import type { ContentChannel, FaqRecord } from "./types";

export function FaqsView() {
  const [items, setItems] = useState<FaqRecord[]>([]);
  const [savedOrder, setSavedOrder] = useState<string[]>([]);
  const [channels, setChannels] = useState<ContentChannel[]>([]);
  const [searchDraft, setSearchDraft] = useState("");
  const [search, setSearch] = useState("");
  const [channelId, setChannelId] = useState("");
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [deleting, setDeleting] = useState(false);
  const [error, setError] = useState("");
  const [editorOpen, setEditorOpen] = useState(false);
  const [editing, setEditing] = useState<FaqRecord | null>(null);
  const [deleteTarget, setDeleteTarget] = useState<FaqRecord | null>(null);
  const [expandedId, setExpandedId] = useState<string | null>(null);
  const [draggingId, setDraggingId] = useState<string | null>(null);
  const orderChanged = items.some((item, index) => savedOrder[index] !== item.id);
  const canReorder = !search && !channelId;

  const load = useCallback(async (signal?: AbortSignal) => {
    setLoading(true);
    setError("");
    try {
      const [faqRecords, channelRecords] = await Promise.all([
        fetchFaqs({ search, channelId }, signal),
        fetchCmsChannels(signal),
      ]);
      setItems(faqRecords);
      setSavedOrder(faqRecords.map((item) => item.id));
      setChannels(channelRecords);
    } catch (cause) {
      if (cause instanceof DOMException && cause.name === "AbortError") return;
      setError(cause instanceof Error ? cause.message : "Unable to load FAQs.");
    } finally {
      setLoading(false);
    }
  }, [search, channelId]);

  useEffect(() => {
    const controller = new AbortController();
    Promise.all([fetchFaqs({ search, channelId }, controller.signal), fetchCmsChannels(controller.signal)])
      .then(([faqRecords, channelRecords]) => {
        setItems(faqRecords);
        setSavedOrder(faqRecords.map((item) => item.id));
        setChannels(channelRecords);
        setError("");
      })
      .catch((cause: unknown) => {
        if (cause instanceof DOMException && cause.name === "AbortError") return;
        setError(cause instanceof Error ? cause.message : "Unable to load FAQs.");
      })
      .finally(() => {
        if (!controller.signal.aborted) setLoading(false);
      });
    return () => controller.abort();
  }, [search, channelId]);

  async function saveFaq(values: Parameters<typeof createFaq>[0]) {
    setSaving(true);
    try {
      if (editing) {
        await updateFaq(editing.id, values);
        toast.success("FAQ updated successfully.");
      } else {
        await createFaq(values);
        toast.success("FAQ created successfully.");
      }
      setEditorOpen(false);
      setEditing(null);
      await load();
    } finally {
      setSaving(false);
    }
  }

  async function confirmDelete() {
    if (!deleteTarget) return;
    setDeleting(true);
    try {
      await deleteFaq(deleteTarget.id);
      setDeleteTarget(null);
      await load();
    } catch (cause) {
      setError(cause instanceof Error ? cause.message : "Unable to delete this FAQ.");
      setDeleteTarget(null);
    } finally {
      setDeleting(false);
    }
  }

  function moveItem(id: string, targetIndex: number) {
    setItems((current) => moveFaqOrder(current, id, targetIndex));
  }

  async function saveOrder() {
    setSaving(true);
    setError("");
    try {
      await reorderFaqs(items.map((item, index) => ({ id: item.id, order: index + 1 })));
      await load();
    } catch (cause) {
      setError(cause instanceof Error ? cause.message : "Unable to save the FAQ order.");
    } finally {
      setSaving(false);
    }
  }

  function applySearch() {
    const nextSearch = searchDraft.trim();
    if (nextSearch === search) {
      void load();
      return;
    }
    setLoading(true);
    setSearch(nextSearch);
  }

  return (
    <section className="rounded-xl border bg-card shadow-sm">
      <div className="flex flex-col gap-4 border-b p-5 sm:p-6">
        <div className="flex flex-wrap items-center justify-between gap-3">
          <div>
            <h2 className="text-lg font-semibold">FAQ configuration</h2>
            <p className="mt-1 text-sm text-muted-foreground">Manage the questions and answers shown to EV drivers.</p>
          </div>
          <Button onClick={() => { setEditing(null); setEditorOpen(true); }} disabled={loading}>
            <Plus aria-hidden="true" /> Add FAQ
          </Button>
        </div>
        <div className="flex flex-col gap-2 sm:flex-row sm:items-center">
          <div className="relative min-w-0 flex-1">
            <Search aria-hidden="true" className="absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
            <Input value={searchDraft} onChange={(event) => setSearchDraft(event.target.value)} onKeyDown={(event) => { if (event.key === "Enter") applySearch(); }} placeholder="Search questions…" aria-label="Search FAQs" className="pl-9" />
          </div>
          <select aria-label="Filter FAQs by channel" value={channelId} onChange={(event) => { setLoading(true); setChannelId(event.target.value); }} className="h-11 rounded-lg border border-input bg-card px-3 text-sm outline-none focus:border-primary sm:w-56">
            <option value="">All channels</option>
            {channels.map((channel) => <option key={channel.id} value={channel.id}>{channel.name}</option>)}
          </select>
          <Button variant="outline" onClick={applySearch}>Search</Button>
          <Button variant="outline" size="icon" onClick={() => void load()} disabled={loading} aria-label="Refresh FAQs"><RefreshCw aria-hidden="true" className={loading ? "animate-spin motion-reduce:animate-none" : ""} /></Button>
        </div>
      </div>

      <div className="p-5 sm:p-6">
        {error && <p role="alert" className="mb-4 rounded-lg border border-destructive/30 bg-destructive/10 p-3 text-sm text-destructive">{error}</p>}
        {orderChanged && canReorder && (
          <div className="mb-4 flex flex-wrap items-center justify-between gap-3 rounded-lg border border-primary/30 bg-primary/5 p-3">
            <p className="text-sm">FAQ order changed. Save it to update how the list is displayed.</p>
            <div className="flex gap-2">
              <Button type="button" variant="outline" disabled={saving} onClick={() => setItems((current) => [...current].sort((a, b) => savedOrder.indexOf(a.id) - savedOrder.indexOf(b.id)))}>Cancel</Button>
              <Button type="button" disabled={saving} onClick={() => void saveOrder()}>{saving ? "Saving…" : "Save order"}</Button>
            </div>
          </div>
        )}

        {loading ? (
          <div className="space-y-3" aria-label="Loading FAQs">
            {[1, 2, 3].map((row) => <div key={row} className="h-20 animate-pulse rounded-lg border bg-muted/30" />)}
          </div>
        ) : items.length === 0 ? (
          <div className="rounded-lg border border-dashed px-5 py-12 text-center">
            <h3 className="font-medium">No FAQs found</h3>
            <p className="mt-1 text-sm text-muted-foreground">Create an FAQ to get started or change the filters.</p>
          </div>
        ) : (
          <div className="space-y-3" role="list" aria-label="Frequently asked questions">
            {items.map((item, index) => (
              <article
                key={item.id}
                role="listitem"
                onDragOver={(event) => { if (canReorder) event.preventDefault(); }}
                onDrop={(event) => {
                  if (!canReorder) return;
                  event.preventDefault();
                  const movedId = event.dataTransfer.getData("text/plain") || draggingId;
                  if (movedId) moveItem(movedId, index);
                  setDraggingId(null);
                }}
                className={`rounded-lg border bg-background p-4 transition-opacity sm:p-5 ${draggingId === item.id ? "opacity-50" : ""}`}
              >
                <div className="flex items-start gap-3">
                  {canReorder && (
                    <div className="flex shrink-0 flex-col items-center gap-1">
                      <button
                        type="button"
                        draggable={!saving}
                        onDragStart={(event) => { event.dataTransfer.setData("text/plain", item.id); event.dataTransfer.effectAllowed = "move"; setDraggingId(item.id); }}
                        onDragEnd={() => setDraggingId(null)}
                        aria-label={`Drag to reorder FAQ ${item.question}`}
                        className="cursor-grab rounded p-1 text-muted-foreground hover:bg-muted active:cursor-grabbing"
                      ><GripVertical aria-hidden="true" className="size-4" /></button>
                      <button type="button" aria-label={`Move FAQ ${item.question} up`} disabled={index === 0 || saving} onClick={() => moveItem(item.id, index - 1)} className="rounded p-1 text-muted-foreground hover:bg-muted disabled:opacity-30"><ArrowUp aria-hidden="true" className="size-3.5" /></button>
                      <button type="button" aria-label={`Move FAQ ${item.question} down`} disabled={index === items.length - 1 || saving} onClick={() => moveItem(item.id, index + 1)} className="rounded p-1 text-muted-foreground hover:bg-muted disabled:opacity-30"><ArrowDown aria-hidden="true" className="size-3.5" /></button>
                    </div>
                  )}
                  <div className="min-w-0 flex-1">
                    <button type="button" aria-expanded={expandedId === item.id} onClick={() => setExpandedId((current) => current === item.id ? null : item.id)} className="block w-full text-left font-semibold hover:text-primary">{item.question}</button>
                    <div className="mt-2 flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
                      <span>Order {item.order || index + 1}</span>
                      {item.channelIds.length ? item.channelIds.map((id) => <span key={id} className="rounded-full bg-muted px-2 py-1">{channels.find((channel) => channel.id === id)?.name ?? "Channel"}</span>) : <span>All channels</span>}
                    </div>
                    {expandedId === item.id && <div className="mt-4 border-t pt-4"><MarkdownPreview value={item.answer} /></div>}
                  </div>
                  <div className="flex shrink-0 gap-1">
                    <Button type="button" variant="ghost" size="icon-sm" aria-label={`Edit FAQ ${item.question}`} onClick={() => { setEditing(item); setEditorOpen(true); }}><Pencil aria-hidden="true" /></Button>
                    <Button type="button" variant="ghost" size="icon-sm" aria-label={`Delete FAQ ${item.question}`} onClick={() => setDeleteTarget(item)}><Trash2 aria-hidden="true" className="text-destructive" /></Button>
                  </div>
                </div>
              </article>
            ))}
          </div>
        )}
      </div>

      {editorOpen && <FaqEditorDialog key={editing?.id ?? "new"} item={editing} channels={channels} open={editorOpen} busy={saving} onClose={() => { setEditorOpen(false); setEditing(null); }} onSave={saveFaq} />}
      <ConfirmContentDeleteDialog open={!!deleteTarget} title="Delete this FAQ?" description={`“${deleteTarget?.question ?? "This FAQ"}” will be removed from your organization’s content.`} busy={deleting} onClose={() => setDeleteTarget(null)} onConfirm={() => void confirmDelete()} />
    </section>
  );
}
