"use client";

import { useState, useMemo } from "react";
import { ChevronDown, ChevronRight, Archive } from "lucide-react";
import { adminFetch } from "@/lib/csrf";
import { type BookingStatus, type BookingFilter, type BaseBooking, type BookingGroup, sortByStatus } from "./types";
import { EmptyState, BookingCard, ContactLinks, StatusBadge, StatusActions, DeleteBtn } from "./BookingComponents";
import { fmtDate } from "./types";
import { InlineNotes } from "./InlineNotes";
import { useToast } from "./Toast";

interface GenericBookingsListProps<T extends BaseBooking> {
  items: T[];
  endpoint: string;
  filter: BookingFilter;
  onItemsChange: (fn: (prev: T[]) => T[]) => void;
  onDataChange?: () => void;
  groups?: BookingGroup<T>[];
  renderExtra?: (item: T) => React.ReactNode;
  onConfirm?: (id: number) => void;
}

export function GenericBookingsList<T extends BaseBooking>({
  items,
  endpoint,
  filter,
  onItemsChange,
  onDataChange,
  groups,
  renderExtra,
  onConfirm,
}: GenericBookingsListProps<T>) {
  const [showArchived, setShowArchived] = useState(false);
  const [expanded, setExpanded] = useState<Record<string, boolean>>({});
  const { showError } = useToast();

  async function handleStatus(id: number, status: BookingStatus) {
    if (status === "confirmed" && onConfirm) {
      onConfirm(id);
      return;
    }
    const prev = items.find((b) => b.id === id);
    const prevStatus = prev?.status;
    onItemsChange((list) => list.map((b) => b.id === id ? { ...b, status } : b));
    try {
      const res = await adminFetch(endpoint, {
        method: "PUT",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ action: "set-status", id, status }),
      });
      if (!res.ok) throw new Error();
      onDataChange?.();
    } catch {
      if (prevStatus) onItemsChange((list) => list.map((b) => b.id === id ? { ...b, status: prevStatus } : b));
      showError("Не удалось обновить статус");
    }
  }

  async function handleDelete(id: number) {
    try {
      const res = await adminFetch(`${endpoint}?id=${id}`, { method: "DELETE" });
      if (!res.ok) throw new Error();
      onItemsChange((list) => list.filter((b) => b.id !== id));
      onDataChange?.();
    } catch {
      showError("Не удалось удалить запись");
    }
  }

  async function handleNotes(id: number, notes: string) {
    const prev = items.find((b) => b.id === id);
    const prevNotes = prev?.notes;
    onItemsChange((list) => list.map((b) => b.id === id ? { ...b, notes: notes || undefined } : b));
    try {
      const res = await adminFetch(endpoint, {
        method: "PUT",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ action: "set-notes", id, notes }),
      });
      if (!res.ok) throw new Error();
    } catch {
      onItemsChange((list) => list.map((b) => b.id === id ? { ...b, notes: prevNotes } : b));
      showError("Не удалось сохранить заметку");
    }
  }

  function renderItem(item: T, isArchived: boolean) {
    return (
      <BookingCard key={item.id} status={item.status}>
        <div className="flex items-start justify-between gap-3">
          <div className="flex items-center gap-2 flex-wrap text-sm min-w-0">
            <span className="font-medium text-white truncate max-w-[200px]">{item.name}</span>
            <ContactLinks phone={item.phone} instagram={item.instagram} telegram={item.telegram} />
            {renderExtra?.(item)}
          </div>
          <div className="flex items-center gap-2 shrink-0">
            <span className="text-neutral-600 text-xs">{fmtDate(item.createdAt)}</span>
            <DeleteBtn onClick={() => handleDelete(item.id)} name={item.name} />
          </div>
        </div>
        <div className="flex items-center gap-2 mt-2 flex-wrap">
          <StatusBadge status={item.status} />
          {!isArchived && <StatusActions status={item.status} onStatus={(s) => handleStatus(item.id, s)} />}
        </div>
        <InlineNotes value={item.notes || ""} onSave={(notes) => handleNotes(item.id, notes)} />
      </BookingCard>
    );
  }

  if (groups) {
    const filteredGroups = groups.map((g) => ({
      ...g,
      items: filter === "all" ? sortByStatus(g.items) : sortByStatus(g.items.filter((b) => b.status === filter)),
    })).filter((g) => g.items.length > 0);

    const activeGroups = filteredGroups.filter((g) => !g.isArchived);
    const archivedGroups = filteredGroups.filter((g) => g.isArchived);
    const archivedCount = archivedGroups.reduce((sum, g) => sum + g.items.length, 0);
    const allArchived = activeGroups.length === 0 && archivedCount > 0 && filter === "all";

    function renderGroup(group: BookingGroup<T>) {
      const isOpen = expanded[group.key] ?? !group.isArchived;
      const groupCounts = { new: 0, contacted: 0, confirmed: 0, declined: 0 };
      for (const item of group.items) groupCounts[item.status] = (groupCounts[item.status] || 0) + 1;
      return (
        <div key={group.key} className={`rounded-xl border overflow-hidden ${group.isArchived ? "border-white/5 opacity-60" : "border-white/10"}`}>
          <button
            onClick={() => setExpanded((p) => ({ ...p, [group.key]: !isOpen }))}
            className={`w-full flex items-center gap-3 px-4 py-3 transition-colors text-left ${group.isArchived ? "bg-neutral-900/50 hover:bg-neutral-800/50" : "bg-neutral-900 hover:bg-neutral-800/80"}`}
          >
            {isOpen ? <ChevronDown size={14} className="text-neutral-500 shrink-0" /> : <ChevronRight size={14} className="text-neutral-500 shrink-0" />}
            {group.sublabel && (
              <span className={`text-xs font-medium shrink-0 ${group.isArchived ? "text-neutral-500" : "text-gold"}`}>{group.sublabel}</span>
            )}
            <span className={`font-medium text-sm truncate ${group.isArchived ? "text-neutral-400" : "text-white"}`}>{group.label}</span>
            {group.dateBadge && (
              <span className={`text-[10px] rounded-full px-2 py-0.5 shrink-0 ${
                group.isArchived ? "text-neutral-600 bg-neutral-800 line-through" : "text-gold bg-gold/10"
              }`}>
                {group.dateBadge}
              </span>
            )}
            {group.isArchived && (
              <span className="text-[10px] text-neutral-600 bg-neutral-800 rounded-full px-2 py-0.5 shrink-0">архив</span>
            )}
            <span className="text-[10px] text-neutral-500 bg-neutral-800 rounded-full px-2 py-0.5 shrink-0">{group.items.length} чел.</span>
            {!group.isArchived && (
              <div className="flex gap-2 ml-auto text-[10px]">
                {groupCounts.new > 0 && <span className="text-gold">{groupCounts.new} новых</span>}
                {groupCounts.contacted > 0 && <span className="text-blue-400">{groupCounts.contacted} связ.</span>}
                {groupCounts.confirmed > 0 && <span className="text-emerald-400">{groupCounts.confirmed} подтв.</span>}
              </div>
            )}
          </button>
          {isOpen && (
            <div className="px-4 pb-3 pt-1 space-y-2">
              {group.items.map((item) => renderItem(item, group.isArchived))}
            </div>
          )}
        </div>
      );
    }

    return (
      <div>
        {allArchived && (
          <p className="text-sm text-neutral-500 py-4">Все записи в архиве</p>
        )}
        {!allArchived && (
          <div className="space-y-2">
            {activeGroups.length === 0 && archivedGroups.length === 0 && <EmptyState total={items.length} />}
            {activeGroups.map(renderGroup)}
          </div>
        )}
        {archivedCount > 0 && (
          <div className="mt-4">
            <button
              onClick={() => setShowArchived((v) => !v)}
              className="flex items-center gap-2 text-xs text-neutral-500 hover:text-neutral-300 transition-colors"
            >
              <Archive size={13} />
              {(showArchived || allArchived) ? "Скрыть архив" : `Архив (${archivedCount} записей)`}
              {(showArchived || allArchived) ? <ChevronDown size={12} /> : <ChevronRight size={12} />}
            </button>
            {(showArchived || allArchived) && (
              <div className="mt-2 space-y-2">
                {archivedGroups.map(renderGroup)}
              </div>
            )}
          </div>
        )}
      </div>
    );
  }

  const filtered = useMemo(() => {
    const list = filter === "all" ? items : items.filter((b) => b.status === filter);
    return sortByStatus(list);
  }, [items, filter]);

  return (
    <div>
      <div className="space-y-2">
        {filtered.length === 0 && <EmptyState total={items.length} />}
        {filtered.map((item) => renderItem(item, false))}
      </div>
    </div>
  );
}
