import { useState, useEffect } from "react";
import {
  createFileRoute,
  Link,
} from "@tanstack/react-router";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
  ArrowLeft,
  Mail,
  Phone,
  MapPin,
  AlertCircle,
  Hash,
} from "lucide-react";
import { toast } from "sonner";

import type { Client } from "@rubis/shared";
import { api } from "@/lib/api";
import { queryKeys } from "@/lib/queryKeys";
import {
  formatEuros,
  formatDate,
  formatRelativeDate,
} from "@/lib/format";
import { cn } from "@/lib/utils";

import { Card } from "@/components/ui/Card";
import { Eyebrow } from "@/components/ui/Eyebrow";
import { Textarea } from "@/components/ui/Textarea";
import { StatusBadge } from "@/components/ui/StatusBadge";
import { ClientPaidChart } from "@/components/charts/ClientPaidChart";
import type { InvoiceListItem } from "@/components/factures/InvoiceTable";
import type { ClientWithStats } from "@/components/clients/ClientTable";

type ClientTimeseries = {
  range: 3 | 6 | 12;
  granularity: "month" | "week";
  paidByMonth: Array<{
    bucket: string;
    encaisseCents: number;
    paidCount: number;
    dsoDays: number;
  }>;
};

type ClientDetail = ClientWithStats & {
  invoices: InvoiceListItem[];
};

export const Route = createFileRoute("/_app/clients_/$id")({
  component: ClientDetailPage,
  loader: ({ context, params }) => {
    void context.queryClient.prefetchQuery({
      queryKey: queryKeys.clients.detail(params.id),
      queryFn: () =>
        api.get<ClientDetail>(`/api/v1/clients/${params.id}`),
    });
  },
});

function ClientDetailPage() {
  const { id } = Route.useParams();
  const queryClient = useQueryClient();

  const { data: client, isPending, isError } = useQuery({
    queryKey: queryKeys.clients.detail(id),
    queryFn: () => api.get<ClientDetail>(`/api/v1/clients/${id}`),
  });

  const { data: timeseries } = useQuery({
    queryKey: ["clients", id, "timeseries", 6] as const,
    queryFn: () =>
      api.get<ClientTimeseries>(`/api/v1/clients/${id}/timeseries?range=6`),
  });

  // Notes : édition locale + sauvegarde sur blur. Garde le draft local pour
  // ne pas refetch écraser ce que l'user est en train de taper.
  const [notesDraft, setNotesDraft] = useState<string>("");
  useEffect(() => {
    if (client?.notes != null) setNotesDraft(client.notes);
    else setNotesDraft("");
  }, [client?.id]); // eslint-disable-line react-hooks/exhaustive-deps

  const updateNotesMutation = useMutation({
    mutationFn: (notes: string) =>
      api.patch<Client>(`/api/v1/clients/${id}`, { notes }),
    onSuccess: () => {
      void queryClient.invalidateQueries({ queryKey: queryKeys.clients.detail(id) });
      void queryClient.invalidateQueries({ queryKey: queryKeys.clients.all() });
    },
    onError: () => {
      toast.error("Notes non sauvegardées. Réessayez.");
    },
  });

  if (isError) {
    return (
      <div className="text-center py-12">
        <p className="font-display text-[20px] font-semibold text-ink">
          Client introuvable.
        </p>
        <Link
          to="/clients"
          className="mt-3 inline-block text-[13px] text-rubis underline-offset-4 hover:underline"
        >
          ← Retour aux clients
        </Link>
      </div>
    );
  }

  if (isPending || !client) {
    return <ClientDetailSkeleton />;
  }

  const hasLate = client.lateInvoiceCount > 0;

  return (
    <div className="flex flex-col gap-6">
      <Link
        to="/clients"
        className="inline-flex items-center gap-1.5 self-start text-[12.5px] text-ink-3 hover:text-rubis"
      >
        <ArrowLeft size={13} aria-hidden="true" /> Clients
      </Link>

      <header>
        <Eyebrow>{hasLate ? "Retards récurrents" : "Client"}</Eyebrow>
        <h1 className="mt-2 font-display text-[28px] font-bold tracking-[-0.022em] text-ink lg:text-[32px]">
          {client.name}
        </h1>
        <div className="mt-3 flex flex-wrap items-center gap-x-4 gap-y-1 text-[13px] text-ink-2">
          <span className="inline-flex items-center gap-1.5">
            <Mail size={13} className="text-ink-3" aria-hidden="true" />
            <a
              href={`mailto:${client.email}`}
              className="hover:text-rubis hover:underline underline-offset-4"
            >
              {client.email}
            </a>
          </span>
          {client.phone && (
            <span className="inline-flex items-center gap-1.5">
              <Phone size={13} className="text-ink-3" aria-hidden="true" />
              {client.phone}
            </span>
          )}
          {client.siret && (
            <span className="inline-flex items-center gap-1.5">
              <Hash size={13} className="text-ink-3" aria-hidden="true" />
              <span className="tabular-nums">{client.siret}</span>
            </span>
          )}
          {client.address && (
            <span className="inline-flex items-center gap-1.5">
              <MapPin size={13} className="text-ink-3" aria-hidden="true" />
              <span className="truncate max-w-[260px]">{client.address}</span>
            </span>
          )}
        </div>
      </header>

      {/* Stats clés en grille — 4 colonnes desktop, 2 mobile */}
      <section
        aria-label="Statistiques client"
        className="grid grid-cols-2 gap-3 lg:grid-cols-4 lg:gap-4"
      >
        <StatBlock
          label="Factures actives"
          value={String(client.activeInvoiceCount)}
          accent={hasLate ? "warning" : "neutral"}
          tail={
            hasLate ? (
              <span className="inline-flex items-center gap-1 text-[12px] font-medium text-rubis-deep">
                <AlertCircle size={11} aria-hidden="true" />
                {client.lateInvoiceCount} en retard
              </span>
            ) : undefined
          }
        />
        <StatBlock
          label="En attente"
          value={
            client.pendingLifetimeCents > 0
              ? formatEuros(client.pendingLifetimeCents)
              : "—"
          }
        />
        <StatBlock
          label="Encaissé total"
          value={
            client.paidLifetimeCents > 0
              ? formatEuros(client.paidLifetimeCents)
              : "—"
          }
          accent="positive"
        />
        <StatBlock
          label="Factures payées"
          value={`${client.paidInvoiceCount}/${client.invoiceCount}`}
          tail={
            client.lastActivityAt ? (
              <span className="text-[12px] text-ink-3">
                {formatRelativeDate(client.lastActivityAt)}
              </span>
            ) : undefined
          }
        />
      </section>

      {/* Mini chart "encaissé sur 6 mois" pour ce client */}
      <Card padding="md">
        <div className="flex items-center justify-between mb-3">
          <div>
            <Eyebrow tone="ink">Paiements · 6 mois</Eyebrow>
            <p className="mt-1 text-[12.5px] text-ink-3">
              Évolution des encaissements de ce client.
            </p>
          </div>
        </div>
        <ClientPaidChart
          data={timeseries?.paidByMonth ?? []}
          granularity={timeseries?.granularity}
        />
      </Card>

      <div className="grid grid-cols-1 gap-6 lg:grid-cols-[1.5fr_1fr]">
        {/* Liste des factures du client */}
        <section>
          <Eyebrow tone="ink">Factures</Eyebrow>
          <div className="mt-3">
            {client.invoices.length === 0 ? (
              <Card padding="md" variant="flat">
                <p className="text-[13px] italic text-ink-3 text-center">
                  Aucune facture pour ce client.
                </p>
              </Card>
            ) : (
              <Card padding="none" className="overflow-hidden">
                <ul>
                  {client.invoices.map((invoice) => (
                    <li
                      key={invoice.id}
                      className="border-t border-line first:border-t-0"
                    >
                      <Link
                        to="/factures/$id"
                        params={{ id: invoice.id }}
                        className={cn(
                          "flex items-center justify-between gap-3 px-4 py-3",
                          "transition-colors hover:bg-cream-2/40",
                          "focus-visible:outline-none focus-visible:bg-cream",
                        )}
                      >
                        <div className="min-w-0">
                          <p className="text-[13.5px] font-medium text-ink truncate">
                            {invoice.numero}
                          </p>
                          <p className="text-[11.5px] text-ink-3">
                            Échue le {formatDate(invoice.dueDate)}
                          </p>
                        </div>
                        <div className="flex items-center gap-3 shrink-0">
                          <span className="font-display text-[15px] font-semibold tabular-nums text-ink">
                            {formatEuros(invoice.amountTtcCents)}
                          </span>
                          <StatusBadge status={invoice.status} withoutIcon />
                        </div>
                      </Link>
                    </li>
                  ))}
                </ul>
              </Card>
            )}
          </div>
        </section>

        {/* Sidepanel : notes internes */}
        <aside>
          <Eyebrow tone="ink">Notes internes</Eyebrow>
          <Card padding="md" className="mt-3">
            <Textarea
              value={notesDraft}
              onChange={(e) => setNotesDraft(e.target.value)}
              onBlur={() => {
                if (notesDraft !== (client.notes ?? "")) {
                  updateNotesMutation.mutate(notesDraft);
                }
              }}
              placeholder="Préférences de paiement, contexte, anecdotes…"
              rows={6}
              className="bg-cream-2/40 border-0 focus:bg-white"
            />
            <p className="mt-2 text-[11.5px] italic text-ink-3">
              Sauvegarde automatique. Visible uniquement par vous —
              jamais envoyé au client.
            </p>
          </Card>
        </aside>
      </div>
    </div>
  );
}

type StatAccent = "neutral" | "positive" | "warning";

function StatBlock({
  label,
  value,
  accent = "neutral",
  tail,
}: {
  label: string;
  value: string;
  accent?: StatAccent;
  tail?: React.ReactNode;
}) {
  return (
    <Card padding="md" className="min-w-0">
      <p className="text-[10.5px] font-semibold uppercase tracking-[0.14em] text-ink-3">
        {label}
      </p>
      <p
        className={cn(
          "mt-2 font-display text-[24px] font-bold leading-none tracking-[-0.018em] tabular-nums",
          accent === "warning" ? "text-rubis-deep" : "text-ink",
        )}
      >
        {value}
      </p>
      {tail && <div className="mt-2">{tail}</div>}
      {/* Note : on omet 'positive' visuellement (pas de vert succès, cf. marque) */}
      {accent === "positive" && !tail && <span className="sr-only">Encaissé</span>}
    </Card>
  );
}

function ClientDetailSkeleton() {
  return (
    <div className="flex flex-col gap-6 animate-pulse">
      <div className="h-3 w-20 rounded bg-cream-2" />
      <div className="h-8 w-1/2 rounded bg-cream-2" />
      <div className="h-4 w-1/3 rounded bg-cream-2" />
      <div className="grid grid-cols-2 gap-3 lg:grid-cols-4 lg:gap-4">
        {Array.from({ length: 4 }).map((_, i) => (
          <div key={i} className="h-24 rounded-card bg-cream-2" />
        ))}
      </div>
      <div className="grid grid-cols-1 gap-6 lg:grid-cols-[1.5fr_1fr]">
        <div className="h-72 rounded-card bg-cream-2" />
        <div className="h-72 rounded-card bg-cream-2" />
      </div>
    </div>
  );
}
