import { useEffect, useMemo, useState, type ReactNode } from "react";

import glmLogo from "./assets/glm-logo.png";
import type { SupabaseAuthSession } from "./lib/supabase-auth";
import {
  createContact,
  createObligation,
  loadObligationDeliveryStatuses,
  loadTaxData,
  removeContact,
  removeObligation,
  searchBambooContacts,
  updateContact,
  updateObligation,
  type NewContact,
  type NewObligation,
} from "./lib/supabase-data";
import {
  DAYS_ES,
  MONTHS_ES,
  formatDate,
  getAlertDates,
  normalizeSearch,
  type BambooContactCandidate,
  type Contact,
  type ContactArea,
  type Country,
  type TaxCategory,
  type TaxEvent,
} from "./lib/tax-utils";

type View = "calendar" | "list" | "contacts";
type Toast = { type: "success" | "error"; message: string } | null;

export default function TaxApp({
  session,
  onSignOut,
}: {
  session: SupabaseAuthSession;
  onSignOut: () => void;
}) {
  const [events, setEvents] = useState<TaxEvent[]>([]);
  const [contacts, setContacts] = useState<Contact[]>([]);
  const [countries, setCountries] = useState<Country[]>([]);
  const [loading, setLoading] = useState(true);
  const [busy, setBusy] = useState(false);
  const [toast, setToast] = useState<Toast>(null);
  const [view, setView] = useState<View>("calendar");
  const today = new Date();
  const [year, setYear] = useState(today.getFullYear());
  const [month, setMonth] = useState(today.getMonth());
  const [showAddEvent, setShowAddEvent] = useState(false);
  const [selectedDay, setSelectedDay] = useState<string | null>(null);
  const [selectedEvent, setSelectedEvent] = useState<TaxEvent | null>(null);
  const [showContactManager, setShowContactManager] = useState(false);
  const [selectedContact, setSelectedContact] = useState<Contact | null>(null);

  useEffect(() => {
    let cancelled = false;
    const initialize = async () => {
      try {
        const data = await loadTaxData(session);
        if (cancelled) return;
        setCountries(data.countries);
        setEvents(data.events);
        setContacts(data.contacts);
      } catch {
        if (!cancelled) setToast({ type: "error", message: "No pudimos cargar la información." });
      } finally {
        if (!cancelled) setLoading(false);
      }
    };
    void initialize();
    return () => {
      cancelled = true;
    };
  }, [session]);

  useEffect(() => {
    let cancelled = false;

    const refreshDeliveryStatus = async () => {
      try {
        const statuses = await loadObligationDeliveryStatuses(session);
        if (cancelled) return;
        const statusMap = new Map(statuses.map((status) => [status.obligationId, status]));
        const applyStatus = (event: TaxEvent): TaxEvent => {
          const status = statusMap.get(event.id);
          if (!status) return event;
          return {
            ...event,
            hasSentNotification: status.hasSentNotification,
            firstSentAt: status.firstSentAt,
            sentNotificationCount: status.sentNotificationCount,
          };
        };
        setEvents((current) => current.map(applyStatus));
        setSelectedEvent((current) => (current ? applyStatus(current) : null));
      } catch {
        // La protección definitiva también existe en Supabase.
      }
    };

    const interval = window.setInterval(() => void refreshDeliveryStatus(), 60_000);
    const handleFocus = () => void refreshDeliveryStatus();
    window.addEventListener("focus", handleFocus);

    return () => {
      cancelled = true;
      window.clearInterval(interval);
      window.removeEventListener("focus", handleFocus);
    };
  }, [session]);

  useEffect(() => {
    if (!toast) return;
    const timeout = window.setTimeout(() => setToast(null), 3800);
    return () => window.clearTimeout(timeout);
  }, [toast]);

  const eventsByDay = useMemo(() => {
    const map: Record<string, TaxEvent[]> = {};
    for (const event of events) (map[event.date] ||= []).push(event);
    return map;
  }, [events]);

  const monthEvents = useMemo(
    () =>
      events
        .filter((event) => {
          const [eventYear, eventMonth] = event.date.split("-").map(Number);
          return eventYear === year && eventMonth - 1 === month;
        })
        .sort((a, b) => a.date.localeCompare(b.date) || a.text.localeCompare(b.text)),
    [events, month, year],
  );

  const previousMonth = () => {
    if (month === 0) {
      setMonth(11);
      setYear((value) => value - 1);
    } else {
      setMonth((value) => value - 1);
    }
  };

  const nextMonth = () => {
    if (month === 11) {
      setMonth(0);
      setYear((value) => value + 1);
    } else {
      setMonth((value) => value + 1);
    }
  };

  const handleCreateEvent = async (input: NewObligation) => {
    setBusy(true);
    try {
      const created = await createObligation(session, input);
      setEvents((current) => [...current, created]);
      setShowAddEvent(false);
      setToast({ type: "success", message: "Obligación guardada." });
    } catch (error) {
      setToast({
        type: "error",
        message: error instanceof Error ? error.message : "No pudimos guardar la obligación.",
      });
    } finally {
      setBusy(false);
    }
  };

  const handleUpdateEvent = async (id: string, input: NewObligation) => {
    setBusy(true);
    try {
      const updated = await updateObligation(session, id, input);
      setEvents((current) => current.map((event) => (event.id === id ? updated : event)));
      setSelectedEvent(null);
      setToast({ type: "success", message: "Obligación actualizada." });
    } catch (error) {
      setToast({
        type: "error",
        message: error instanceof Error ? error.message : "No pudimos actualizar la obligación.",
      });
    } finally {
      setBusy(false);
    }
  };

  const handleDeleteEvent = async (id: string) => {
    if (!window.confirm("¿Eliminar esta obligación?")) return;
    setBusy(true);
    try {
      await removeObligation(session, id);
      setEvents((current) => current.filter((event) => event.id !== id));
      setSelectedEvent(null);
      setToast({ type: "success", message: "Obligación eliminada." });
    } catch {
      setToast({ type: "error", message: "No pudimos eliminar la obligación." });
    } finally {
      setBusy(false);
    }
  };

  const handleCreateContact = async (input: NewContact) => {
    setBusy(true);
    try {
      const created = await createContact(session, input);
      setContacts((current) => [...current, created]);
      setShowContactManager(false);
      setToast({ type: "success", message: "Contacto guardado." });
    } catch (error) {
      setToast({
        type: "error",
        message: error instanceof Error ? error.message : "No pudimos guardar el contacto.",
      });
    } finally {
      setBusy(false);
    }
  };

  const handleUpdateContact = async (id: string, input: NewContact) => {
    setBusy(true);
    try {
      const updated = await updateContact(session, id, input);
      setContacts((current) => current.map((contact) => (contact.id === id ? updated : contact)));
      setSelectedContact(null);
      setToast({ type: "success", message: "Contacto actualizado." });
    } catch (error) {
      setToast({
        type: "error",
        message: error instanceof Error ? error.message : "No pudimos actualizar el contacto.",
      });
    } finally {
      setBusy(false);
    }
  };

  const handleBambooSearch = async (fullName: string) => searchBambooContacts(session, fullName);

  const handleDeleteContact = async (id: string) => {
    if (!window.confirm("¿Eliminar este contacto?")) return;
    setBusy(true);
    try {
      await removeContact(session, id);
      setContacts((current) => current.filter((contact) => contact.id !== id));
      setSelectedContact(null);
      setToast({ type: "success", message: "Contacto eliminado." });
    } catch {
      setToast({ type: "error", message: "No pudimos eliminar el contacto." });
    } finally {
      setBusy(false);
    }
  };

  return (
    <div className="flex h-dvh min-h-0 flex-col overflow-hidden bg-background">
      <Header
        onAdd={() => {
          setSelectedDay(null);
          setShowAddEvent(true);
        }}
        view={view}
        setView={setView}
        onSignOut={onSignOut}
      />

      <main className="app-scrollbar-hidden mx-auto min-h-0 w-full max-w-7xl flex-1 overflow-y-auto px-4 py-6 sm:px-6 lg:px-8">
        {loading ? (
          <LoadingData />
        ) : view === "calendar" ? (
          <CalendarView
            year={year}
            month={month}
            eventsByDay={eventsByDay}
            onPrev={previousMonth}
            onNext={nextMonth}
            onToday={() => {
              setYear(today.getFullYear());
              setMonth(today.getMonth());
            }}
            onDayClick={(iso) => {
              if (iso < isoToday()) {
                setToast({
                  type: "error",
                  message: "No puedes crear una obligación en una fecha que ya pasó.",
                });
                return;
              }
              setSelectedDay(iso);
              setShowAddEvent(true);
            }}
            onEventOpen={setSelectedEvent}
          />
        ) : view === "list" ? (
          <ListView
            events={monthEvents}
            year={year}
            month={month}
            onPrev={previousMonth}
            onNext={nextMonth}
            onEventOpen={setSelectedEvent}
          />
        ) : (
          <ContactsView
            countries={countries}
            contacts={contacts}
            onAdd={() => setShowContactManager(true)}
            onOpen={setSelectedContact}
            onDelete={handleDeleteContact}
          />
        )}
      </main>

      {showAddEvent && (
        <AddEventModal
          countries={countries.filter((country) => !country.isRegional)}
          defaultDate={selectedDay ?? isoToday()}
          busy={busy}
          onClose={() => setShowAddEvent(false)}
          onSave={handleCreateEvent}
        />
      )}

      {selectedEvent && (
        <EventDetailsModal
          event={selectedEvent}
          countries={countries.filter((country) => !country.isRegional)}
          busy={busy}
          onClose={() => setSelectedEvent(null)}
          onSave={(input) => handleUpdateEvent(selectedEvent.id, input)}
          onDelete={() => handleDeleteEvent(selectedEvent.id)}
        />
      )}

      {showContactManager && (
        <ContactManagerModal
          countries={countries}
          busy={busy}
          onClose={() => setShowContactManager(false)}
          onSearch={handleBambooSearch}
          onSave={handleCreateContact}
        />
      )}

      {selectedContact && (
        <EditContactModal
          contact={selectedContact}
          countries={countries}
          busy={busy}
          onClose={() => setSelectedContact(null)}
          onSave={(input) => handleUpdateContact(selectedContact.id, input)}
          onDelete={() => handleDeleteContact(selectedContact.id)}
        />
      )}

      {toast && <ToastMessage toast={toast} />}
    </div>
  );
}

function Header({
  onAdd,
  onSignOut,
  view,
  setView,
}: {
  onAdd: () => void;
  onSignOut: () => void;
  view: View;
  setView: (view: View) => void;
}) {
  const tabs: { id: View; label: string }[] = [
    { id: "calendar", label: "Calendario" },
    { id: "list", label: "Lista" },
    { id: "contacts", label: "Contactos" },
  ];

  return (
    <header className="sticky top-0 z-20 border-b border-border bg-card/90 backdrop-blur">
      <div className="mx-auto flex max-w-7xl items-center gap-4 px-4 py-3 sm:px-6 lg:px-8">
        <img
          src={glmLogo}
          alt="GomezLee Marketing"
          className="h-8 w-auto shrink-0 object-contain sm:h-9"
        />
        <div className="min-w-0 flex-1">
          <h1 className="truncate text-base font-semibold leading-tight text-glm-blue sm:text-lg">
            Seguimiento de Impuestos GLM
          </h1>
          <p className="hidden text-xs text-muted-foreground sm:block">
            Calendario tributario regional · GomezLee Marketing
          </p>
        </div>
        <nav className="hidden gap-1 rounded-lg bg-muted p-1 md:flex">
          {tabs.map((tab) => (
            <button
              key={tab.id}
              onClick={() => setView(tab.id)}
              className={
                "rounded-md px-3 py-1.5 text-sm font-medium transition-colors " +
                (view === tab.id
                  ? "bg-card text-glm-blue shadow-sm"
                  : "text-muted-foreground hover:text-foreground")
              }
            >
              {tab.label}
            </button>
          ))}
        </nav>
        <button
          onClick={onAdd}
          className="inline-flex items-center gap-1.5 rounded-lg bg-glm-green px-3 py-2 text-sm font-medium text-white shadow-sm transition-transform hover:-translate-y-px hover:bg-glm-green/90"
        >
          <PlusIcon />
          <span className="hidden sm:inline">Añadir</span>
        </button>
        <button
          type="button"
          onClick={onSignOut}
          aria-label="Cerrar sesión"
          title="Cerrar sesión"
          className="inline-flex items-center gap-1.5 rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2 text-sm font-semibold text-destructive shadow-sm transition hover:-translate-y-px hover:border-destructive hover:bg-destructive hover:text-white"
        >
          <LogoutIcon />
          <span className="hidden lg:inline">Cerrar sesión</span>
        </button>
      </div>
      <nav className="mx-auto flex max-w-7xl gap-1 border-t border-border px-4 py-2 md:hidden">
        {tabs.map((tab) => (
          <button
            key={tab.id}
            onClick={() => setView(tab.id)}
            className={
              "flex-1 rounded-md px-2 py-1.5 text-sm font-medium transition-colors " +
              (view === tab.id ? "bg-glm-blue-soft text-glm-blue" : "text-muted-foreground")
            }
          >
            {tab.label}
          </button>
        ))}
      </nav>
    </header>
  );
}

function CalendarView({
  year,
  month,
  eventsByDay,
  onPrev,
  onNext,
  onToday,
  onDayClick,
  onEventOpen,
}: {
  year: number;
  month: number;
  eventsByDay: Record<string, TaxEvent[]>;
  onPrev: () => void;
  onNext: () => void;
  onToday: () => void;
  onDayClick: (iso: string) => void;
  onEventOpen: (event: TaxEvent) => void;
}) {
  const cells = buildMonthGrid(year, month);
  const todayIso = isoToday();
  const [expandedDay, setExpandedDay] = useState<{ iso: string; events: TaxEvent[] } | null>(null);

  return (
    <div>
      <MonthNav year={year} month={month} onPrev={onPrev} onNext={onNext} onToday={onToday} />
      <div className="overflow-hidden rounded-2xl border border-border bg-card shadow-sm">
        <div className="grid grid-cols-7 border-b border-border bg-muted/60 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
          {DAYS_ES.map((day) => (
            <div key={day} className="px-2 py-2 text-center">
              {day}
            </div>
          ))}
        </div>
        <div className="grid grid-cols-7">
          {cells.map((cell, index) => {
            const inMonth = cell.month === month;
            const dayEvents = eventsByDay[cell.iso] ?? [];
            const isToday = cell.iso === todayIso;
            const isWednesday = cell.dow === 2;
            return (
              <div
                key={index}
                onClick={() => onDayClick(cell.iso)}
                className={
                  "group relative min-h-[110px] cursor-pointer border-b border-r border-border p-2 transition-colors " +
                  (inMonth ? "bg-card" : "bg-muted/30") +
                  (isWednesday && inMonth ? " bg-glm-blue-soft/40" : "") +
                  " hover:bg-glm-blue-soft/60"
                }
              >
                <div className="mb-1 flex items-center justify-between">
                  <span
                    className={
                      "inline-flex h-6 min-w-6 items-center justify-center rounded-full px-1.5 text-xs font-semibold " +
                      (isToday
                        ? "bg-glm-green text-white"
                        : inMonth
                          ? "text-foreground"
                          : "text-muted-foreground/60")
                    }
                  >
                    {cell.day}
                  </span>
                  {isWednesday && inMonth && (
                    <span className="text-[9px] font-semibold uppercase tracking-wider text-glm-blue">
                      Mié
                    </span>
                  )}
                </div>
                <div className="space-y-1">
                  {dayEvents.slice(0, 3).map((event) => (
                    <EventChip key={event.id} event={event} onOpen={onEventOpen} />
                  ))}
                  {dayEvents.length > 3 && (
                    <button
                      type="button"
                      onClick={(clickEvent) => {
                        clickEvent.stopPropagation();
                        setExpandedDay({ iso: cell.iso, events: dayEvents });
                      }}
                      className="inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[10px] font-semibold text-glm-blue transition hover:bg-glm-blue-soft hover:underline"
                      aria-label={`Ver ${dayEvents.length - 3} obligaciones adicionales del ${formatDate(cell.iso)}`}
                    >
                      +{dayEvents.length - 3} más · Ver todos
                    </button>
                  )}
                </div>
              </div>
            );
          })}
        </div>
      </div>
      <Legend />
      {expandedDay && (
        <DayEventsModal
          date={expandedDay.iso}
          events={expandedDay.events}
          onClose={() => setExpandedDay(null)}
          onEventOpen={(event) => {
            setExpandedDay(null);
            onEventOpen(event);
          }}
        />
      )}
    </div>
  );
}

function DayEventsModal({
  date,
  events,
  onClose,
  onEventOpen,
}: {
  date: string;
  events: TaxEvent[];
  onClose: () => void;
  onEventOpen: (event: TaxEvent) => void;
}) {
  const sortedEvents = [...events].sort(
    (a, b) => a.category.localeCompare(b.category) || a.text.localeCompare(b.text),
  );

  return (
    <ModalShell onClose={onClose} title={`Obligaciones · ${formatDate(date)}`}>
      <p className="mb-4 text-sm text-muted-foreground">
        Selecciona una obligación para consultar su información completa.
      </p>
      <div className="space-y-2">
        {sortedEvents.map((event) => (
          <button
            key={event.id}
            type="button"
            onClick={() => onEventOpen(event)}
            className="flex w-full items-start gap-3 rounded-xl border border-border bg-card p-3 text-left transition hover:border-glm-blue/35 hover:bg-glm-blue-soft/25"
          >
            <span
              className={
                "mt-1 h-2.5 w-2.5 shrink-0 rounded-full " +
                (event.category === "nomina" ? "bg-glm-orange" : "bg-glm-blue")
              }
            />
            <span className="min-w-0 flex-1">
              <span className="mb-1 flex flex-wrap items-center gap-2">
                <CategoryBadge category={event.category} />
                <span className="rounded-full bg-muted px-2 py-0.5 text-[11px] font-medium text-muted-foreground">
                  {event.country}
                </span>
                {event.hasSentNotification && (
                  <span className="inline-flex items-center gap-1 rounded-full bg-glm-green/15 px-2 py-0.5 text-[11px] font-semibold text-glm-green">
                    <LockIcon size={11} /> Solo lectura
                  </span>
                )}
              </span>
              <span className="block text-sm font-medium leading-snug text-foreground">
                {event.text}
              </span>
            </span>
            <ChevronIcon dir="right" />
          </button>
        ))}
      </div>
    </ModalShell>
  );
}

function MonthNav({
  year,
  month,
  onPrev,
  onNext,
  onToday,
}: {
  year: number;
  month: number;
  onPrev: () => void;
  onNext: () => void;
  onToday: () => void;
}) {
  return (
    <div className="mb-4 flex flex-wrap items-center justify-between gap-3">
      <h2 className="text-2xl font-semibold tracking-tight text-glm-blue">
        {MONTHS_ES[month]} <span className="text-muted-foreground">{year}</span>
      </h2>
      <div className="flex items-center gap-2">
        <button
          onClick={onToday}
          className="rounded-md border border-border bg-card px-3 py-1.5 text-sm font-medium text-glm-blue hover:bg-glm-blue-soft"
        >
          Hoy
        </button>
        <div className="flex overflow-hidden rounded-md border border-border">
          <button
            onClick={onPrev}
            aria-label="Mes anterior"
            className="border-r border-border bg-card p-2 hover:bg-muted"
          >
            <ChevronIcon dir="left" />
          </button>
          <button
            onClick={onNext}
            aria-label="Mes siguiente"
            className="bg-card p-2 hover:bg-muted"
          >
            <ChevronIcon dir="right" />
          </button>
        </div>
      </div>
    </div>
  );
}

function Legend() {
  return (
    <div className="mt-4 flex flex-wrap items-center gap-4 text-xs text-muted-foreground">
      <span className="inline-flex items-center gap-1.5">
        <span className="h-2.5 w-2.5 rounded-full bg-glm-orange" /> Nómina
      </span>
      <span className="inline-flex items-center gap-1.5">
        <span className="h-2.5 w-2.5 rounded-full bg-glm-blue" /> Administración
      </span>
      <span className="inline-flex items-center gap-1.5">
        <span className="h-2.5 w-2.5 rounded-full bg-glm-green" /> Hoy
      </span>
      <span className="inline-flex items-center gap-1.5">
        <span className="h-2.5 w-2.5 rounded-sm bg-glm-blue-soft" /> Miércoles de alerta
      </span>
    </div>
  );
}

function ListView({
  events,
  year,
  month,
  onPrev,
  onNext,
  onEventOpen,
}: {
  events: TaxEvent[];
  year: number;
  month: number;
  onPrev: () => void;
  onNext: () => void;
  onEventOpen: (event: TaxEvent) => void;
}) {
  const [category, setCategory] = useState<"all" | TaxCategory>("all");
  const [search, setSearch] = useState("");
  const searchValue = normalizeSearch(search);
  const filtered = events.filter((event) => {
    const categoryMatches = category === "all" || event.category === category;
    const searchMatches =
      !searchValue || normalizeSearch(`${event.text} ${event.country}`).includes(searchValue);
    return categoryMatches && searchMatches;
  });

  return (
    <div>
      <MonthNav
        year={year}
        month={month}
        onPrev={onPrev}
        onNext={onNext}
        onToday={() => undefined}
      />
      <div className="mb-4 grid gap-3 lg:grid-cols-[minmax(0,1fr)_auto] lg:items-center">
        <SearchField
          value={search}
          onChange={setSearch}
          placeholder="Buscar obligación por nombre o país..."
        />
        <div className="flex flex-wrap gap-2">
          {(
            [
              { id: "all", label: `Todos (${events.length})` },
              {
                id: "nomina",
                label: `Nómina (${events.filter((event) => event.category === "nomina").length})`,
              },
              {
                id: "admin",
                label: `Administración (${events.filter((event) => event.category === "admin").length})`,
              },
            ] as const
          ).map((filter) => (
            <button
              key={filter.id}
              onClick={() => setCategory(filter.id)}
              className={
                "rounded-full border px-3 py-1.5 text-xs font-medium transition-colors " +
                (category === filter.id
                  ? "border-glm-blue bg-glm-blue text-white"
                  : "border-border bg-card text-muted-foreground hover:text-foreground")
              }
            >
              {filter.label}
            </button>
          ))}
        </div>
      </div>
      {filtered.length === 0 ? (
        <EmptyState message="No encontramos obligaciones con esos filtros." />
      ) : (
        <ul className="space-y-2">
          {filtered.map((event) => (
            <li key={event.id}>
              <EventRow event={event} onOpen={onEventOpen} />
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

function EventRow({ event, onOpen }: { event: TaxEvent; onOpen: (event: TaxEvent) => void }) {
  const alerts = getAlertDates(event.date);
  return (
    <button
      type="button"
      onClick={() => onOpen(event)}
      className="flex w-full flex-col gap-3 rounded-xl border border-border bg-card p-4 text-left shadow-sm transition hover:-translate-y-px hover:border-glm-blue/30 hover:shadow-md sm:flex-row sm:items-center"
    >
      <div className="flex min-w-[110px] flex-col items-center rounded-lg bg-glm-blue-soft/50 px-3 py-2">
        <span className="text-[10px] font-semibold uppercase tracking-wider text-glm-blue">
          {MONTHS_ES[Number(event.date.slice(5, 7)) - 1].slice(0, 3)}
        </span>
        <span className="text-2xl font-bold leading-none text-glm-blue">
          {Number(event.date.slice(8, 10))}
        </span>
        <span className="mt-0.5 text-[10px] font-medium text-muted-foreground">
          {dayName(event.date)}
        </span>
      </div>
      <div className="min-w-0 flex-1">
        <div className="mb-1 flex flex-wrap items-center gap-2">
          <CategoryBadge category={event.category} />
          <span className="rounded-full bg-muted px-2 py-0.5 text-[11px] font-medium text-muted-foreground">
            {event.country}
          </span>
          {event.hasSentNotification && (
            <span className="inline-flex items-center gap-1 rounded-full bg-glm-green/15 px-2 py-0.5 text-[11px] font-semibold text-glm-green">
              <LockIcon /> Aviso enviado · Solo lectura
            </span>
          )}
        </div>
        <p className="text-sm font-medium text-foreground">{event.text}</p>
        <div className="mt-2 flex flex-wrap gap-1.5 text-[11px]">
          <span className="text-muted-foreground">Alertas:</span>
          {alerts.map((alert) => (
            <span
              key={alert}
              className={
                "rounded-md px-1.5 py-0.5 font-medium " +
                (alert === event.date
                  ? "bg-glm-orange/15 text-glm-orange"
                  : "bg-glm-green/15 text-glm-green")
              }
            >
              {formatDate(alert)}
            </span>
          ))}
        </div>
      </div>
      <span
        className="self-start rounded-md p-2 text-muted-foreground sm:self-center"
        aria-hidden="true"
      >
        {event.hasSentNotification ? <LockIcon size={18} /> : <EditIcon />}
      </span>
    </button>
  );
}

function EventChip({ event, onOpen }: { event: TaxEvent; onOpen: (event: TaxEvent) => void }) {
  const color =
    event.category === "nomina"
      ? "bg-glm-orange/15 text-glm-orange border-glm-orange/30"
      : "bg-glm-blue-soft text-glm-blue border-glm-blue/20";
  return (
    <button
      type="button"
      onClick={(clickEvent) => {
        clickEvent.stopPropagation();
        onOpen(event);
      }}
      className={`flex w-full items-center gap-1 truncate rounded-md border px-1.5 py-0.5 text-left text-[10.5px] font-medium leading-tight hover:opacity-80 ${color}`}
      title={`${event.country}: ${event.text}${event.hasSentNotification ? " · Aviso enviado" : ""}`}
    >
      {event.hasSentNotification && <LockIcon size={11} />}
      <span className="truncate">{event.text}</span>
    </button>
  );
}

function CategoryBadge({ category }: { category: TaxCategory }) {
  const payroll = category === "nomina";
  return (
    <span
      className={
        "inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide " +
        (payroll ? "bg-glm-orange/15 text-glm-orange" : "bg-glm-blue-soft text-glm-blue")
      }
    >
      <span className={"h-1.5 w-1.5 rounded-full " + (payroll ? "bg-glm-orange" : "bg-glm-blue")} />
      {payroll ? "Nómina" : "Administración"}
    </span>
  );
}

function ContactsView({
  countries,
  contacts,
  onAdd,
  onOpen,
  onDelete,
}: {
  countries: Country[];
  contacts: Contact[];
  onAdd: () => void;
  onOpen: (contact: Contact) => void;
  onDelete: (id: string) => void;
}) {
  const [selectedCountry, setSelectedCountry] = useState("all");
  const [search, setSearch] = useState("");
  const searchValue = normalizeSearch(search);
  const visibleCountries = countries.filter(
    (country) => selectedCountry === "all" || country.id === selectedCountry,
  );

  const contactsByCountry = useMemo(() => {
    const map = new Map<string, Contact[]>();
    for (const country of countries) map.set(country.id, []);
    for (const contact of contacts) (map.get(contact.countryId) ?? []).push(contact);
    for (const list of map.values()) list.sort((a, b) => a.name.localeCompare(b.name));
    return map;
  }, [contacts, countries]);

  return (
    <div>
      <div className="mb-5 flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between">
        <div>
          <h2 className="text-2xl font-semibold tracking-tight text-glm-blue">
            Contactos por país
          </h2>
          <p className="mt-1 max-w-3xl text-sm text-muted-foreground">
            Busca empleados en BambooHR o agrégalos manualmente. Los datos importados siempre se
            pueden revisar y modificar antes o después de guardar.
          </p>
        </div>
        <button
          type="button"
          onClick={onAdd}
          className="inline-flex shrink-0 items-center justify-center gap-1.5 rounded-lg bg-glm-green px-4 py-2.5 text-sm font-semibold text-white shadow-sm transition hover:-translate-y-px hover:bg-glm-green/90"
        >
          <PlusIcon /> Agregar contacto
        </button>
      </div>

      <div className="mb-6 grid gap-3 md:grid-cols-2">
        <CountryFilter
          countries={countries}
          value={selectedCountry}
          onChange={setSelectedCountry}
        />
        <SearchField
          value={search}
          onChange={setSearch}
          placeholder="Buscar contacto por nombre..."
        />
      </div>

      <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
        {visibleCountries.map((country) => {
          const countryContacts = (contactsByCountry.get(country.id) ?? []).filter(
            (contact) =>
              !searchValue ||
              normalizeSearch(
                `${contact.name} ${contact.email} ${contact.role} ${contact.department} ${contact.location}`,
              ).includes(searchValue),
          );
          return (
            <section
              key={country.id}
              className="flex min-h-52 flex-col rounded-xl border border-border bg-card p-4 shadow-sm"
            >
              <div className="mb-3 flex items-center justify-between gap-3">
                <div className="min-w-0">
                  <h3 className="truncate font-semibold text-glm-blue">{country.name}</h3>
                  <p className="text-[11px] text-muted-foreground">
                    {countryContacts.length} contacto{countryContacts.length === 1 ? "" : "s"}
                  </p>
                </div>
                <span className="rounded-md bg-glm-green/15 px-2 py-0.5 text-[11px] font-semibold text-glm-green">
                  {country.code}
                </span>
              </div>

              {countryContacts.length === 0 ? (
                <div className="flex flex-1 items-center justify-center rounded-lg border border-dashed border-border bg-muted/30 px-4 py-6 text-center text-xs text-muted-foreground">
                  {searchValue
                    ? "No hay coincidencias en este país."
                    : "Todavía no hay contactos registrados."}
                </div>
              ) : (
                <ul className="flex-1 space-y-3">
                  {countryContacts.map((contact) => (
                    <li
                      key={contact.id}
                      className="group relative border-t border-border pt-3 first:border-0 first:pt-0"
                    >
                      <button
                        type="button"
                        onClick={() => onOpen(contact)}
                        className="block w-full rounded-lg pr-8 text-left transition hover:bg-muted/45 focus:outline-none focus:ring-2 focus:ring-glm-green/25"
                        aria-label={`Ver y editar ${contact.name}`}
                      >
                        <p className="pr-1 text-sm font-medium text-foreground">{contact.name}</p>
                        <p className="text-xs text-muted-foreground">
                          {contact.role || areaLabel(contact.area)}
                        </p>
                        <div className="mt-1 flex flex-wrap gap-1">
                          <span className="rounded bg-muted px-1.5 py-0.5 text-[10px] font-semibold text-muted-foreground">
                            {areaLabel(contact.area)}
                          </span>
                          {contact.source === "bamboohr" && (
                            <span className="rounded bg-glm-blue-soft px-1.5 py-0.5 text-[10px] font-semibold text-glm-blue">
                              BambooHR
                            </span>
                          )}
                          {contact.emailEnabled && (
                            <span className="rounded bg-glm-blue-soft px-1.5 py-0.5 text-[10px] font-semibold text-glm-blue">
                              Correo
                            </span>
                          )}
                          {contact.googleChatEnabled && (
                            <span className="rounded bg-glm-green/15 px-1.5 py-0.5 text-[10px] font-semibold text-glm-green">
                              Google Chat
                            </span>
                          )}
                          {contact.calendarEnabled && (
                            <span className="rounded bg-glm-orange/10 px-1.5 py-0.5 text-[10px] font-semibold text-glm-orange">
                              Calendar
                            </span>
                          )}
                        </div>
                        {contact.email && (
                          <span className="mt-1 block truncate text-xs text-glm-blue">
                            {contact.email}
                          </span>
                        )}
                      </button>
                      <button
                        type="button"
                        onClick={() => onDelete(contact.id)}
                        className="absolute right-0 top-2 rounded p-1 text-muted-foreground opacity-100 transition hover:bg-destructive/10 hover:text-destructive sm:opacity-0 sm:group-hover:opacity-100"
                        aria-label={`Eliminar ${contact.name}`}
                      >
                        <TrashIcon />
                      </button>
                    </li>
                  ))}
                </ul>
              )}
            </section>
          );
        })}
      </div>
    </div>
  );
}

function CountryFilter({
  countries,
  value,
  onChange,
}: {
  countries: Country[];
  value: string;
  onChange: (value: string) => void;
}) {
  const [open, setOpen] = useState(false);
  const [search, setSearch] = useState("");
  const selected = countries.find((country) => country.id === value);
  const normalized = normalizeSearch(search);
  const options = countries.filter(
    (country) => !normalized || normalizeSearch(country.name).includes(normalized),
  );

  return (
    <div className="relative">
      <button
        type="button"
        onClick={() => setOpen((current) => !current)}
        className="flex w-full items-center justify-between rounded-xl border border-border bg-card px-4 py-3 text-left text-sm shadow-sm transition hover:border-glm-blue/30"
      >
        <span>
          <span className="font-semibold text-glm-blue">País:</span>{" "}
          <span className="text-foreground">{selected?.name ?? "Todos"}</span>
        </span>
        <ChevronDownIcon />
      </button>
      {open && (
        <div className="absolute z-30 mt-2 w-full overflow-hidden rounded-xl border border-border bg-card shadow-xl">
          <div className="border-b border-border p-2">
            <SearchField value={search} onChange={setSearch} placeholder="Buscar país..." compact />
          </div>
          <div className="app-scrollbar-hidden max-h-64 overflow-y-auto p-2">
            <FilterOption
              label="Todos"
              selected={value === "all"}
              onClick={() => {
                onChange("all");
                setOpen(false);
                setSearch("");
              }}
            />
            {options.map((country) => (
              <FilterOption
                key={country.id}
                label={country.name}
                selected={value === country.id}
                onClick={() => {
                  onChange(country.id);
                  setOpen(false);
                  setSearch("");
                }}
              />
            ))}
          </div>
        </div>
      )}
    </div>
  );
}

function FilterOption({
  label,
  selected,
  onClick,
}: {
  label: string;
  selected: boolean;
  onClick: () => void;
}) {
  return (
    <button
      type="button"
      onClick={onClick}
      className={
        "flex w-full items-center gap-3 rounded-lg px-3 py-2 text-left text-sm transition " +
        (selected
          ? "bg-glm-green/10 font-semibold text-glm-blue"
          : "text-foreground hover:bg-muted")
      }
    >
      <span className="w-4">{selected ? "✓" : ""}</span>
      {label}
    </button>
  );
}

function SearchField({
  value,
  onChange,
  placeholder,
  compact = false,
}: {
  value: string;
  onChange: (value: string) => void;
  placeholder: string;
  compact?: boolean;
}) {
  return (
    <label className="relative block">
      <span className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground">
        <SearchIcon />
      </span>
      <input
        value={value}
        onChange={(event) => onChange(event.target.value)}
        placeholder={placeholder}
        className={`w-full rounded-xl border border-border bg-card pl-10 pr-3 text-sm shadow-sm outline-none transition placeholder:text-muted-foreground/75 focus:border-glm-green focus:ring-2 focus:ring-glm-green/20 ${compact ? "py-2" : "py-3"}`}
      />
    </label>
  );
}

function AddEventModal({
  countries,
  defaultDate,
  busy,
  onClose,
  onSave,
}: {
  countries: Country[];
  defaultDate: string;
  busy: boolean;
  onClose: () => void;
  onSave: (input: NewObligation) => void;
}) {
  const [date, setDate] = useState(defaultDate);
  const [text, setText] = useState("");
  const [category, setCategory] = useState<TaxCategory>("admin");
  const [countryId, setCountryId] = useState("");
  const dateIsPast = date < isoToday();
  const alerts = getAlertDates(date);

  return (
    <ModalShell onClose={onClose} title="Nueva obligación tributaria">
      <form
        onSubmit={(event) => {
          event.preventDefault();
          if (!text.trim() || !countryId || dateIsPast) return;
          onSave({ date, text: text.trim(), category, countryId });
        }}
        className="space-y-4"
      >
        <Field label="Fecha límite">
          <input
            type="date"
            value={date}
            min={isoToday()}
            onChange={(event) => setDate(event.target.value)}
            className={inputClass}
            required
          />
        </Field>
        {dateIsPast && (
          <p className="rounded-lg border border-destructive/20 bg-destructive/5 px-3 py-2 text-xs font-medium text-destructive">
            No puedes crear una obligación en una fecha que ya pasó.
          </p>
        )}
        <Field label="Descripción">
          <textarea
            value={text}
            onChange={(event) => setText(event.target.value)}
            rows={3}
            placeholder="Ej.: ISV, Ret. 12.5 %, Ret. 1 %, ISR"
            className={inputClass}
            required
          />
        </Field>
        <div className="grid gap-3 sm:grid-cols-2">
          <Field label="Categoría">
            <select
              value={category}
              onChange={(event) => setCategory(event.target.value as TaxCategory)}
              className={inputClass}
            >
              <option value="nomina">Nómina</option>
              <option value="admin">Administración</option>
            </select>
          </Field>
          <Field label="País">
            <select
              value={countryId}
              onChange={(event) => setCountryId(event.target.value)}
              className={inputClass}
              required
            >
              <option value="" disabled>
                Seleccionar país
              </option>
              {countries.map((country) => (
                <option key={country.id} value={country.id}>
                  {country.name}
                </option>
              ))}
            </select>
          </Field>
        </div>
        <div className="rounded-lg bg-glm-blue-soft/50 p-3">
          <p className="mb-1 text-[11px] font-semibold uppercase tracking-wide text-glm-blue">
            Se generarán estas alertas
          </p>
          <div className="flex flex-wrap gap-1.5 text-xs">
            {alerts.map((alert) => (
              <span
                key={alert}
                className={
                  "rounded-md px-2 py-0.5 font-medium " +
                  (alert === date
                    ? "bg-glm-orange/15 text-glm-orange"
                    : "bg-glm-green/20 text-glm-green")
                }
              >
                {formatDate(alert)} · {dayName(alert)}
              </span>
            ))}
          </div>
          <p className="mt-2 text-[11px] text-muted-foreground">
            Regla: miércoles anterior y el mismo día, incluidos sábados y domingos.
          </p>
        </div>
        <ModalActions busy={busy || dateIsPast} onCancel={onClose} submitLabel="Guardar" />
      </form>
    </ModalShell>
  );
}

function EventDetailsModal({
  event,
  countries,
  busy,
  onClose,
  onSave,
  onDelete,
}: {
  event: TaxEvent;
  countries: Country[];
  busy: boolean;
  onClose: () => void;
  onSave: (input: NewObligation) => void;
  onDelete: () => void;
}) {
  const [date, setDate] = useState(event.date);
  const [text, setText] = useState(event.text);
  const [category, setCategory] = useState<TaxCategory>(event.category);
  const [countryId, setCountryId] = useState(event.countryId);
  const alerts = getAlertDates(date);
  const locked = event.hasSentNotification;
  const historicalPast = event.date < isoToday();
  const invalidPastDate = date < isoToday() && date !== event.date;

  if (locked) {
    return (
      <ModalShell onClose={onClose} title="Detalle de obligación tributaria">
        <div className="space-y-4">
          <div className="flex gap-3 rounded-xl border border-glm-green/25 bg-glm-green/10 p-4">
            <span className="mt-0.5 shrink-0 text-glm-green">
              <LockIcon size={20} />
            </span>
            <div>
              <p className="text-sm font-semibold text-glm-blue">
                Aviso enviado · Evento bloqueado
              </p>
              <p className="mt-1 text-xs leading-relaxed text-muted-foreground">
                Esta obligación ya generó un recordatorio y se conserva únicamente como consulta. Ya
                no puede modificarse ni eliminarse.
              </p>
              {event.firstSentAt && (
                <p className="mt-2 text-[11px] font-medium text-glm-green">
                  Primer envío registrado: {formatDateTime(event.firstSentAt)}
                </p>
              )}
            </div>
          </div>

          <div className="grid gap-3 sm:grid-cols-2">
            <ReadOnlyValue
              label="Fecha límite"
              value={`${formatDate(event.date)} · ${dayName(event.date)}`}
            />
            <ReadOnlyValue label="País" value={event.country} />
          </div>
          <ReadOnlyValue label="Descripción" value={event.text} multiline />
          <ReadOnlyValue
            label="Categoría"
            value={event.category === "nomina" ? "Nómina" : "Administración"}
          />

          <div className="rounded-lg bg-glm-blue-soft/50 p-3">
            <p className="mb-1 text-[11px] font-semibold uppercase tracking-wide text-glm-blue">
              Fechas de alerta
            </p>
            <div className="flex flex-wrap gap-1.5 text-xs">
              {getAlertDates(event.date).map((alert) => (
                <span
                  key={alert}
                  className={
                    "rounded-md px-2 py-0.5 font-medium " +
                    (alert === event.date
                      ? "bg-glm-orange/15 text-glm-orange"
                      : "bg-glm-green/20 text-glm-green")
                  }
                >
                  {formatDate(alert)} · {dayName(alert)}
                </span>
              ))}
            </div>
          </div>

          <div className="flex justify-end pt-2">
            <button
              type="button"
              onClick={onClose}
              className="rounded-md bg-glm-blue px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-glm-blue/90"
            >
              Cerrar
            </button>
          </div>
        </div>
      </ModalShell>
    );
  }

  return (
    <ModalShell onClose={onClose} title="Editar obligación tributaria">
      <form
        onSubmit={(submitEvent) => {
          submitEvent.preventDefault();
          if (!text.trim() || !countryId || invalidPastDate) return;
          onSave({ date, text: text.trim(), category, countryId });
        }}
        className="space-y-4"
      >
        <div className="flex gap-3 rounded-xl border border-glm-blue/15 bg-glm-blue-soft/45 p-3">
          <span className="mt-0.5 shrink-0 text-glm-blue">
            <EditIcon />
          </span>
          <p className="text-xs leading-relaxed text-muted-foreground">
            Todavía no se han enviado avisos de esta obligación. Puedes actualizarla o eliminarla.
          </p>
        </div>
        <Field label="Fecha límite">
          <input
            type="date"
            value={date}
            min={historicalPast ? undefined : isoToday()}
            disabled={historicalPast}
            onChange={(changeEvent) => setDate(changeEvent.target.value)}
            className={inputClass}
            required
          />
        </Field>
        {historicalPast && (
          <p className="rounded-lg border border-glm-blue/15 bg-glm-blue-soft/35 px-3 py-2 text-xs text-muted-foreground">
            Esta es una obligación histórica. Su fecha pasada se conserva y no puede moverse a otra
            fecha vencida.
          </p>
        )}
        {invalidPastDate && (
          <p className="rounded-lg border border-destructive/20 bg-destructive/5 px-3 py-2 text-xs font-medium text-destructive">
            No puedes mover una obligación a una fecha que ya pasó.
          </p>
        )}
        <Field label="Descripción">
          <textarea
            value={text}
            onChange={(changeEvent) => setText(changeEvent.target.value)}
            rows={3}
            className={inputClass}
            required
          />
        </Field>
        <div className="grid gap-3 sm:grid-cols-2">
          <Field label="Categoría">
            <select
              value={category}
              onChange={(changeEvent) => setCategory(changeEvent.target.value as TaxCategory)}
              className={inputClass}
            >
              <option value="nomina">Nómina</option>
              <option value="admin">Administración</option>
            </select>
          </Field>
          <Field label="País">
            <select
              value={countryId}
              onChange={(changeEvent) => setCountryId(changeEvent.target.value)}
              className={inputClass}
              required
            >
              {countries.map((country) => (
                <option key={country.id} value={country.id}>
                  {country.name}
                </option>
              ))}
            </select>
          </Field>
        </div>
        <div className="rounded-lg bg-glm-blue-soft/50 p-3">
          <p className="mb-1 text-[11px] font-semibold uppercase tracking-wide text-glm-blue">
            Se generarán estas alertas
          </p>
          <div className="flex flex-wrap gap-1.5 text-xs">
            {alerts.map((alert) => (
              <span
                key={alert}
                className={
                  "rounded-md px-2 py-0.5 font-medium " +
                  (alert === date
                    ? "bg-glm-orange/15 text-glm-orange"
                    : "bg-glm-green/20 text-glm-green")
                }
              >
                {formatDate(alert)} · {dayName(alert)}
              </span>
            ))}
          </div>
          <p className="mt-2 text-[11px] text-muted-foreground">
            Regla: miércoles anterior y el mismo día, incluidos sábados y domingos.
          </p>
        </div>
        <div className="flex flex-col-reverse gap-2 pt-2 sm:flex-row sm:items-center sm:justify-between">
          <button
            type="button"
            onClick={onDelete}
            disabled={busy}
            className="inline-flex items-center justify-center gap-1.5 rounded-md border border-destructive/30 bg-destructive/5 px-4 py-2 text-sm font-semibold text-destructive hover:border-destructive hover:bg-destructive hover:text-white disabled:opacity-60"
          >
            <TrashIcon /> Eliminar
          </button>
          <div className="flex justify-end gap-2">
            <button
              type="button"
              onClick={onClose}
              disabled={busy}
              className="rounded-md border border-border bg-card px-4 py-2 text-sm font-medium text-muted-foreground hover:bg-muted disabled:opacity-60"
            >
              Cancelar
            </button>
            <button
              type="submit"
              disabled={busy || invalidPastDate}
              className="rounded-md bg-glm-green px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-glm-green/90 disabled:cursor-wait disabled:opacity-60"
            >
              {busy ? "Guardando…" : "Guardar cambios"}
            </button>
          </div>
        </div>
      </form>
    </ModalShell>
  );
}

function ReadOnlyValue({
  label,
  value,
  multiline = false,
}: {
  label: string;
  value: string;
  multiline?: boolean;
}) {
  return (
    <div>
      <p className="mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
        {label}
      </p>
      <div
        className={
          "rounded-lg border border-border bg-muted/35 px-3 py-2 text-sm text-foreground " +
          (multiline ? "min-h-20 whitespace-pre-wrap" : "")
        }
      >
        {value}
      </div>
    </div>
  );
}

type ContactDraft = NewContact;

function ContactManagerModal({
  countries,
  busy,
  onClose,
  onSearch,
  onSave,
}: {
  countries: Country[];
  busy: boolean;
  onClose: () => void;
  onSearch: (fullName: string) => Promise<BambooContactCandidate[]>;
  onSave: (input: NewContact) => void;
}) {
  const [mode, setMode] = useState<"bamboo" | "manual">("bamboo");
  const [stage, setStage] = useState<"search" | "results" | "form">("search");
  const [query, setQuery] = useState("");
  const [candidates, setCandidates] = useState<BambooContactCandidate[]>([]);
  const [searching, setSearching] = useState(false);
  const [searchError, setSearchError] = useState("");
  const [draft, setDraft] = useState<ContactDraft>(() => emptyContactDraft(countries));

  const selectCandidate = (candidate: BambooContactCandidate) => {
    setDraft(candidateToContactDraft(candidate, countries));
    setStage("form");
  };

  const runSearch = async () => {
    const fullName = query.trim();
    if (fullName.split(/\s+/).length < 2) {
      setSearchError("Escribe el nombre y apellido de la persona.");
      return;
    }

    setSearching(true);
    setSearchError("");
    try {
      const matches = await onSearch(fullName);
      setCandidates(matches);
      if (matches.length === 1) selectCandidate(matches[0]);
      else setStage("results");
    } catch (error) {
      setSearchError(
        error instanceof Error ? error.message : "No pudimos completar la búsqueda en BambooHR.",
      );
    } finally {
      setSearching(false);
    }
  };

  const switchMode = (nextMode: "bamboo" | "manual") => {
    setMode(nextMode);
    setSearchError("");
    if (nextMode === "manual") {
      setDraft(emptyContactDraft(countries));
      setStage("form");
    } else {
      setStage("search");
    }
  };

  return (
    <ModalShell onClose={searching ? () => undefined : onClose} title="Agregar contacto">
      <div className="relative">
        <div className="mb-5 grid grid-cols-2 gap-1 rounded-xl bg-muted p-1">
          <button
            type="button"
            onClick={() => switchMode("bamboo")}
            disabled={searching || busy}
            className={
              "rounded-lg px-3 py-2 text-sm font-semibold transition " +
              (mode === "bamboo"
                ? "bg-card text-glm-blue shadow-sm"
                : "text-muted-foreground hover:text-foreground")
            }
          >
            Buscar en BambooHR
          </button>
          <button
            type="button"
            onClick={() => switchMode("manual")}
            disabled={searching || busy}
            className={
              "rounded-lg px-3 py-2 text-sm font-semibold transition " +
              (mode === "manual"
                ? "bg-card text-glm-blue shadow-sm"
                : "text-muted-foreground hover:text-foreground")
            }
          >
            Agregar manualmente
          </button>
        </div>

        {mode === "bamboo" && stage === "search" && (
          <form
            onSubmit={(event) => {
              event.preventDefault();
              void runSearch();
            }}
            className="space-y-4"
          >
            <div className="rounded-xl border border-glm-blue/15 bg-glm-blue-soft/35 p-4">
              <p className="text-sm font-semibold text-glm-blue">Búsqueda automática</p>
              <p className="mt-1 text-xs leading-relaxed text-muted-foreground">
                Escribe el nombre completo. La app consultará BambooHR y propondrá país, área, cargo
                y correo. Podrás modificar todo antes de guardar.
              </p>
            </div>
            <Field label="Nombre completo">
              <input
                value={query}
                onChange={(event) => setQuery(event.target.value)}
                className={inputClass}
                placeholder="Ej.: Iveth Herrera"
                autoFocus
                required
              />
            </Field>
            {searchError && (
              <p className="rounded-lg border border-destructive/20 bg-destructive/5 px-3 py-2 text-xs font-medium text-destructive">
                {searchError}
              </p>
            )}
            <ModalActions busy={searching} onCancel={onClose} submitLabel="Buscar empleado" />
          </form>
        )}

        {mode === "bamboo" && stage === "results" && (
          <div className="space-y-4">
            <div>
              <p className="text-sm font-semibold text-glm-blue">
                {candidates.length === 0
                  ? "No encontramos coincidencias"
                  : `${candidates.length} coincidencia${candidates.length === 1 ? "" : "s"}`}
              </p>
              <p className="mt-1 text-xs text-muted-foreground">
                {candidates.length === 0
                  ? "Revisa el nombre o continúa con el registro manual."
                  : "Revisa los detalles y selecciona a la persona correcta."}
              </p>
            </div>

            {candidates.length > 0 && (
              <div className="app-scrollbar-hidden max-h-[52vh] space-y-2 overflow-y-auto pr-1">
                {candidates.map((candidate) => (
                  <button
                    key={`${candidate.id}-${candidate.employeeNumber}`}
                    type="button"
                    onClick={() => selectCandidate(candidate)}
                    className="w-full rounded-xl border border-border bg-card p-4 text-left transition hover:border-glm-green hover:bg-glm-green/5"
                  >
                    <div className="flex items-start justify-between gap-3">
                      <div className="min-w-0">
                        <p className="font-semibold text-foreground">{candidate.fullName}</p>
                        <p className="mt-0.5 text-xs text-muted-foreground">
                          {candidate.jobTitle || "Cargo no registrado"}
                        </p>
                      </div>
                      <span
                        className={
                          "shrink-0 rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide " +
                          (candidate.matchQuality === "exacta"
                            ? "bg-glm-green/15 text-glm-green"
                            : candidate.matchQuality === "alta"
                              ? "bg-glm-blue-soft text-glm-blue"
                              : "bg-muted text-muted-foreground")
                        }
                      >
                        Coincidencia {candidate.matchQuality}
                      </span>
                    </div>
                    <div className="mt-3 grid gap-1.5 text-xs text-muted-foreground sm:grid-cols-2">
                      <span>
                        <strong className="text-foreground">País:</strong>{" "}
                        {candidate.countryName || "Regional"}
                      </span>
                      <span>
                        <strong className="text-foreground">Área:</strong>{" "}
                        {areaLabel(candidate.area)}
                      </span>
                      <span>
                        <strong className="text-foreground">Correo:</strong>{" "}
                        {candidate.email || "No registrado"}
                      </span>
                      <span>
                        <strong className="text-foreground">Departamento:</strong>{" "}
                        {candidate.department || "No registrado"}
                      </span>
                      <span>
                        <strong className="text-foreground">Estado:</strong>{" "}
                        {candidate.status || "No registrado"}
                      </span>
                    </div>
                  </button>
                ))}
              </div>
            )}

            <div className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-between">
              <button
                type="button"
                onClick={() => setStage("search")}
                className="rounded-md border border-border bg-card px-4 py-2 text-sm font-medium text-muted-foreground hover:bg-muted"
              >
                Volver a buscar
              </button>
              <button
                type="button"
                onClick={() => switchMode("manual")}
                className="rounded-md bg-glm-blue px-4 py-2 text-sm font-semibold text-white hover:bg-glm-blue/90"
              >
                Agregar manualmente
              </button>
            </div>
          </div>
        )}

        {stage === "form" && (
          <ContactForm
            countries={countries}
            draft={draft}
            setDraft={setDraft}
            busy={busy}
            onCancel={onClose}
            onSubmit={onSave}
            submitLabel="Guardar contacto"
            imported={draft.source === "bamboohr"}
            onBack={mode === "bamboo" ? () => setStage("results") : undefined}
          />
        )}

        {searching && (
          <div className="absolute -inset-5 z-20 flex flex-col items-center justify-center rounded-xl bg-card/95 px-6 text-center backdrop-blur-sm">
            <span className="h-10 w-10 animate-spin rounded-full border-4 border-glm-blue-soft border-t-glm-green" />
            <p className="mt-4 text-sm font-semibold text-glm-blue">Buscando en BambooHR…</p>
            <p className="mt-1 max-w-xs text-xs leading-relaxed text-muted-foreground">
              Estamos revisando los empleados y comparando las coincidencias. No cierres esta
              ventana.
            </p>
          </div>
        )}
      </div>
    </ModalShell>
  );
}

function EditContactModal({
  contact,
  countries,
  busy,
  onClose,
  onSave,
  onDelete,
}: {
  contact: Contact;
  countries: Country[];
  busy: boolean;
  onClose: () => void;
  onSave: (input: NewContact) => void;
  onDelete: () => void;
}) {
  const [draft, setDraft] = useState<ContactDraft>(() => contactToDraft(contact));

  return (
    <ModalShell onClose={onClose} title="Editar contacto">
      <ContactForm
        countries={countries}
        draft={draft}
        setDraft={setDraft}
        busy={busy}
        onCancel={onClose}
        onSubmit={onSave}
        submitLabel="Guardar cambios"
        imported={contact.source === "bamboohr"}
        onDelete={onDelete}
      />
    </ModalShell>
  );
}

function ContactForm({
  countries,
  draft,
  setDraft,
  busy,
  onCancel,
  onSubmit,
  submitLabel,
  imported,
  onBack,
  onDelete,
}: {
  countries: Country[];
  draft: ContactDraft;
  setDraft: (draft: ContactDraft) => void;
  busy: boolean;
  onCancel: () => void;
  onSubmit: (input: NewContact) => void;
  submitLabel: string;
  imported: boolean;
  onBack?: () => void;
  onDelete?: () => void;
}) {
  const selectedCountry = countries.find((country) => country.id === draft.countryId);
  const update = <K extends keyof ContactDraft>(key: K, value: ContactDraft[K]) =>
    setDraft({ ...draft, [key]: value });

  useEffect(() => {
    if (!selectedCountry?.isRegional && draft.area === "regional") {
      setDraft({ ...draft, area: "admin" });
    }
  }, [draft, selectedCountry, setDraft]);

  const invalid =
    !draft.name.trim() ||
    !draft.countryId ||
    ((draft.emailEnabled || draft.googleChatEnabled || draft.calendarEnabled) &&
      !draft.email.trim());

  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        if (invalid) return;
        onSubmit({
          ...draft,
          name: draft.name.trim(),
          email: draft.email.trim(),
          role: draft.role.trim(),
        });
      }}
      className="space-y-4"
    >
      {imported && (
        <div className="flex gap-3 rounded-xl border border-glm-green/25 bg-glm-green/10 p-3">
          <span className="mt-0.5 h-2.5 w-2.5 shrink-0 rounded-full bg-glm-green" />
          <div>
            <p className="text-xs font-semibold text-glm-blue">Datos encontrados en BambooHR</p>
            <p className="mt-1 text-[11px] leading-relaxed text-muted-foreground">
              Revisa la información antes de guardar. Todos los campos continúan siendo editables.
            </p>
          </div>
        </div>
      )}

      <div className="grid gap-3 sm:grid-cols-2">
        <Field label="País">
          <select
            value={draft.countryId}
            onChange={(event) => update("countryId", event.target.value)}
            className={inputClass}
            required
          >
            {countries.map((country) => (
              <option key={country.id} value={country.id}>
                {country.name}
              </option>
            ))}
          </select>
        </Field>
        <Field label="Área">
          <select
            value={draft.area}
            onChange={(event) => update("area", event.target.value as ContactArea)}
            className={inputClass}
          >
            {selectedCountry?.isRegional && (
              <option value="regional">Regional · todas las categorías</option>
            )}
            <option value="nomina">
              {selectedCountry?.isRegional ? "Nómina · todos los países" : "Nómina"}
            </option>
            <option value="admin">
              {selectedCountry?.isRegional ? "Administración · todos los países" : "Administración"}
            </option>
            <option value="other">Otra</option>
          </select>
        </Field>
      </div>

      {draft.area === "other" && (
        <p className="rounded-lg border border-glm-orange/20 bg-glm-orange/5 px-3 py-2 text-[11px] leading-relaxed text-muted-foreground">
          El área “Otra” conserva la información del empleado, pero no recibe obligaciones hasta que
          se cambie a Nómina, Administración o Regional.
        </p>
      )}

      <Field label="Nombre completo">
        <input
          value={draft.name}
          onChange={(event) => update("name", event.target.value)}
          className={inputClass}
          required
        />
      </Field>

      <div className="grid gap-3 sm:grid-cols-2">
        <Field label="Cargo">
          <input
            value={draft.role}
            onChange={(event) => update("role", event.target.value)}
            className={inputClass}
            placeholder="Ej.: Coordinador Administrativo"
          />
        </Field>
        <Field label="Departamento">
          <input
            value={draft.department ?? ""}
            onChange={(event) => update("department", event.target.value)}
            className={inputClass}
          />
        </Field>
      </div>

      <div className="grid gap-3 sm:grid-cols-2">
        <Field label="División">
          <input
            value={draft.division ?? ""}
            onChange={(event) => update("division", event.target.value)}
            className={inputClass}
          />
        </Field>
        <Field label="Ubicación BambooHR">
          <input
            value={draft.location ?? ""}
            onChange={(event) => update("location", event.target.value)}
            className={inputClass}
          />
        </Field>
      </div>

      <Field label="Correo corporativo">
        <input
          type="email"
          value={draft.email}
          onChange={(event) => update("email", event.target.value)}
          className={inputClass}
          required={draft.emailEnabled || draft.googleChatEnabled || draft.calendarEnabled}
          placeholder="persona@gomezleemarketing.com"
        />
      </Field>

      <div className="flex flex-wrap gap-x-5 gap-y-3 rounded-lg bg-muted/60 p-3 text-sm">
        <CheckToggle
          checked={draft.emailEnabled}
          onChange={(value) => update("emailEnabled", value)}
          label="Enviar por correo"
        />
        <CheckToggle
          checked={draft.googleChatEnabled}
          onChange={(value) => update("googleChatEnabled", value)}
          label="Enviar por Google Chat"
        />
        <CheckToggle
          checked={draft.calendarEnabled}
          onChange={(value) => update("calendarEnabled", value)}
          label="Invitar en Google Calendar"
        />
      </div>

      {imported && (draft.bambooEmployeeNumber || draft.bambooStatus) && (
        <div className="grid gap-2 rounded-lg border border-border bg-muted/25 p-3 text-[11px] text-muted-foreground sm:grid-cols-2">
          <span>
            <strong className="text-foreground">Empleado:</strong>{" "}
            {draft.bambooEmployeeNumber || "No disponible"}
          </span>
          <span>
            <strong className="text-foreground">Estado BambooHR:</strong>{" "}
            {draft.bambooStatus || "No disponible"}
          </span>
        </div>
      )}

      <div className="flex flex-col-reverse gap-2 pt-2 sm:flex-row sm:items-center sm:justify-between">
        <div className="flex gap-2">
          {onDelete && (
            <button
              type="button"
              onClick={onDelete}
              disabled={busy}
              className="inline-flex items-center justify-center gap-1.5 rounded-md border border-destructive/30 bg-destructive/5 px-4 py-2 text-sm font-semibold text-destructive hover:border-destructive hover:bg-destructive hover:text-white disabled:opacity-60"
            >
              <TrashIcon /> Eliminar
            </button>
          )}
          {onBack && (
            <button
              type="button"
              onClick={onBack}
              disabled={busy}
              className="rounded-md border border-border bg-card px-4 py-2 text-sm font-medium text-muted-foreground hover:bg-muted disabled:opacity-60"
            >
              Volver
            </button>
          )}
        </div>
        <div className="flex justify-end gap-2">
          <button
            type="button"
            onClick={onCancel}
            disabled={busy}
            className="rounded-md border border-border bg-card px-4 py-2 text-sm font-medium text-muted-foreground hover:bg-muted disabled:opacity-60"
          >
            Cancelar
          </button>
          <button
            type="submit"
            disabled={busy || invalid}
            className="rounded-md bg-glm-green px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-glm-green/90 disabled:cursor-wait disabled:opacity-60"
          >
            {busy ? "Guardando…" : submitLabel}
          </button>
        </div>
      </div>
    </form>
  );
}

function emptyContactDraft(countries: Country[]): ContactDraft {
  const regional = countries.find((country) => country.isRegional) ?? countries[0];
  return {
    countryId: regional?.id ?? "",
    name: "",
    email: "",
    role: "",
    area: regional?.isRegional ? "regional" : "admin",
    department: "",
    division: "",
    location: "",
    source: "manual",
    bambooEmployeeId: "",
    bambooEmployeeNumber: "",
    bambooStatus: "",
    emailEnabled: true,
    googleChatEnabled: true,
    calendarEnabled: true,
  };
}

function candidateToContactDraft(
  candidate: BambooContactCandidate,
  countries: Country[],
): ContactDraft {
  const country =
    countries.find((item) => item.code === candidate.countryCode) ??
    countries.find((item) => item.isRegional) ??
    countries[0];
  return {
    countryId: country?.id ?? "",
    name: candidate.fullName || candidate.displayName,
    email: candidate.email,
    role: candidate.jobTitle,
    area: candidate.area,
    department: candidate.department,
    division: candidate.division,
    location: candidate.location,
    source: "bamboohr",
    bambooEmployeeId: candidate.id,
    bambooEmployeeNumber: candidate.employeeNumber,
    bambooStatus: candidate.status,
    emailEnabled: Boolean(candidate.email),
    googleChatEnabled: Boolean(candidate.email),
    calendarEnabled: Boolean(candidate.email),
  };
}

function contactToDraft(contact: Contact): ContactDraft {
  return {
    countryId: contact.countryId,
    name: contact.name,
    email: contact.email,
    role: contact.role,
    area: contact.area,
    department: contact.department,
    division: contact.division,
    location: contact.location,
    source: contact.source,
    bambooEmployeeId: contact.bambooEmployeeId,
    bambooEmployeeNumber: contact.bambooEmployeeNumber,
    bambooStatus: contact.bambooStatus,
    emailEnabled: contact.emailEnabled,
    googleChatEnabled: contact.googleChatEnabled,
    calendarEnabled: contact.calendarEnabled,
  };
}

const inputClass =
  "w-full rounded-md border border-input bg-background px-3 py-2 text-sm outline-none transition focus:border-glm-green focus:ring-2 focus:ring-glm-green/30 disabled:cursor-not-allowed disabled:opacity-60";

function ModalShell({
  onClose,
  title,
  children,
}: {
  onClose: () => void;
  title: string;
  children: ReactNode;
}) {
  return (
    <div
      onClick={onClose}
      className="fixed inset-0 z-50 flex items-end justify-center bg-foreground/40 p-0 backdrop-blur-sm sm:items-center sm:p-4"
    >
      <div
        onClick={(event) => event.stopPropagation()}
        className="app-scrollbar-hidden max-h-[94dvh] w-full max-w-xl overflow-y-auto rounded-t-2xl bg-card p-6 shadow-xl sm:rounded-2xl"
      >
        <div className="mb-4 flex items-center justify-between gap-4">
          <h3 className="text-lg font-semibold text-glm-blue">{title}</h3>
          <button
            type="button"
            onClick={onClose}
            className="rounded-md p-1 text-muted-foreground hover:bg-muted"
            aria-label="Cerrar"
          >
            <XIcon />
          </button>
        </div>
        {children}
      </div>
    </div>
  );
}

function Field({ label, children }: { label: string; children: ReactNode }) {
  return (
    <label className="block">
      <span className="mb-1 block text-xs font-semibold uppercase tracking-wide text-muted-foreground">
        {label}
      </span>
      {children}
    </label>
  );
}

function ModalActions({
  busy,
  onCancel,
  submitLabel,
}: {
  busy: boolean;
  onCancel: () => void;
  submitLabel: string;
}) {
  return (
    <div className="flex justify-end gap-2 pt-2">
      <button
        type="button"
        onClick={onCancel}
        disabled={busy}
        className="rounded-md border border-border bg-card px-4 py-2 text-sm font-medium text-muted-foreground hover:bg-muted disabled:opacity-60"
      >
        Cancelar
      </button>
      <button
        type="submit"
        disabled={busy}
        className="rounded-md bg-glm-green px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-glm-green/90 disabled:cursor-wait disabled:opacity-60"
      >
        {busy ? "Guardando…" : submitLabel}
      </button>
    </div>
  );
}

function CheckToggle({
  checked,
  onChange,
  label,
}: {
  checked: boolean;
  onChange: (value: boolean) => void;
  label: string;
}) {
  return (
    <label className="inline-flex cursor-pointer items-center gap-2">
      <input
        type="checkbox"
        checked={checked}
        onChange={(event) => onChange(event.target.checked)}
        className="h-4 w-4 accent-[var(--glm-green)]"
      />
      <span>{label}</span>
    </label>
  );
}

function ToastMessage({ toast }: { toast: Exclude<Toast, null> }) {
  return (
    <div
      className={
        "fixed bottom-5 right-5 z-[70] rounded-xl border px-4 py-3 text-sm font-medium shadow-xl " +
        (toast.type === "success"
          ? "border-glm-green/30 bg-card text-glm-green"
          : "border-destructive/30 bg-card text-destructive")
      }
    >
      {toast.message}
    </div>
  );
}

function LoadingData() {
  return (
    <div className="flex min-h-80 items-center justify-center">
      <div className="text-center">
        <div className="mx-auto h-8 w-8 animate-spin rounded-full border-2 border-glm-blue/20 border-t-glm-green" />
        <p className="mt-4 text-sm text-muted-foreground">Cargando calendario y contactos…</p>
      </div>
    </div>
  );
}

function EmptyState({ message }: { message: string }) {
  return (
    <div className="rounded-xl border border-dashed border-border bg-card/50 p-10 text-center">
      <p className="text-sm text-muted-foreground">{message}</p>
    </div>
  );
}

function areaLabel(area: ContactArea): string {
  if (area === "nomina") return "Nómina";
  if (area === "regional") return "Regional";
  if (area === "other") return "Otra";
  return "Administración";
}

function isoToday(): string {
  const date = new Date();
  return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
}

function formatDateTime(value: string): string {
  return new Intl.DateTimeFormat("es-DO", {
    dateStyle: "medium",
    timeStyle: "short",
    timeZone: "America/Santo_Domingo",
  }).format(new Date(value));
}

function dayName(iso: string): string {
  const [year, month, day] = iso.split("-").map(Number);
  const dow = new Date(Date.UTC(year, month - 1, day)).getUTCDay();
  const map = [6, 0, 1, 2, 3, 4, 5];
  return DAYS_ES[map[dow]];
}

function buildMonthGrid(year: number, month: number) {
  const first = new Date(Date.UTC(year, month, 1));
  const firstDow = (first.getUTCDay() + 6) % 7;
  const start = new Date(first);
  start.setUTCDate(1 - firstDow);
  const cells: { day: number; month: number; year: number; iso: string; dow: number }[] = [];
  for (let index = 0; index < 42; index += 1) {
    const date = new Date(start);
    date.setUTCDate(start.getUTCDate() + index);
    cells.push({
      day: date.getUTCDate(),
      month: date.getUTCMonth(),
      year: date.getUTCFullYear(),
      iso: `${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(2, "0")}-${String(date.getUTCDate()).padStart(2, "0")}`,
      dow: (date.getUTCDay() + 6) % 7,
    });
  }
  return cells;
}

function PlusIcon() {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2.5"
      strokeLinecap="round"
    >
      <path d="M12 5v14M5 12h14" />
    </svg>
  );
}
function LogoutIcon() {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-hidden="true"
    >
      <path d="M10 17l5-5-5-5" />
      <path d="M15 12H3" />
      <path d="M15 3h4a2 2 0 012 2v14a2 2 0 01-2 2h-4" />
    </svg>
  );
}
function ChevronIcon({ dir }: { dir: "left" | "right" }) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2.5"
      strokeLinecap="round"
      strokeLinejoin="round"
    >
      {dir === "left" ? <path d="M15 18l-6-6 6-6" /> : <path d="M9 18l6-6-6-6" />}
    </svg>
  );
}
function ChevronDownIcon() {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
    >
      <path d="m6 9 6 6 6-6" />
    </svg>
  );
}
function XIcon() {
  return (
    <svg
      width="18"
      height="18"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2"
      strokeLinecap="round"
    >
      <path d="M18 6L6 18M6 6l12 12" />
    </svg>
  );
}
function TrashIcon() {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
    >
      <path d="M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2m3 0v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6h14z" />
    </svg>
  );
}
function SearchIcon() {
  return (
    <svg
      width="18"
      height="18"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2"
      strokeLinecap="round"
    >
      <circle cx="11" cy="11" r="8" />
      <path d="m21 21-4.35-4.35" />
    </svg>
  );
}
function LockIcon({ size = 14 }: { size?: number }) {
  return (
    <svg
      width={size}
      height={size}
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-hidden="true"
    >
      <rect x="4" y="10" width="16" height="11" rx="2" />
      <path d="M8 10V7a4 4 0 0 1 8 0v3" />
    </svg>
  );
}
function EditIcon() {
  return (
    <svg
      width="18"
      height="18"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-hidden="true"
    >
      <path d="M12 20h9" />
      <path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z" />
    </svg>
  );
}
