"use client";

import { useState } from "react";
import type { PlanRow } from "@/lib/db/queries/plans";
import { isPerSeatPlan, isPlanEditable } from "@/lib/plans-shared";
import type { PlanFeatureCatalogEntry } from "@/lib/db/queries/plan-features-catalog";
import type { PricingTierRow } from "@/lib/db/queries/pricing-tiers";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { PlanEditModal } from "./plan-edit-modal";

const priceFmt = new Intl.NumberFormat("fr-FR", {
  style: "currency",
  currency: "EUR",
  maximumFractionDigits: 0,
});
const numFmt = new Intl.NumberFormat("fr-FR");

// Libellé d'une tranche per-seat : « 1 → 10 sièges », « 26+ sièges » (max NULL).
function fmtTierRange(tier: PricingTierRow): string {
  if (tier.max_seats == null) return `${tier.min_seats}+ sièges`;
  return `${tier.min_seats} → ${tier.max_seats} sièges`;
}

// Convention métier : -1 = illimité. Affiché ∞ pour faciliter la lecture.
function fmtQuota(n: number): string {
  if (n === -1) return "∞";
  return numFmt.format(n);
}

// Cf. plan-edit-modal.tsx : mysql2 décode les colonnes JSON en JS direct
// (array/object). On accepte string en plus pour rester défensif.
function parseFeatures(raw: unknown): string[] {
  if (raw == null) return [];
  let parsed: unknown = raw;
  if (typeof raw === "string") {
    try {
      parsed = JSON.parse(raw);
    } catch {
      return [];
    }
  }
  if (Array.isArray(parsed))
    return parsed.filter((x): x is string => typeof x === "string");
  if (parsed && typeof parsed === "object") {
    return Object.entries(parsed as Record<string, unknown>)
      .filter(([, v]) => v === true || v === 1 || v === "1")
      .map(([k]) => k);
  }
  return [];
}

export function PlansGrid({
  rows,
  featureCatalog,
  pricingTiers,
}: {
  rows: PlanRow[];
  featureCatalog: PlanFeatureCatalogEntry[];
  pricingTiers: PricingTierRow[];
}) {
  const [editing, setEditing] = useState<PlanRow | null>(null);

  // Map code → label pour rendre les feature codes en libellé FR sur les
  // cartes (sinon on affiche un code technique).
  const labelByCode = new Map(
    featureCatalog.map((f) => [f.code, f.label] as const),
  );

  // Plan actuellement "Le plus populaire" — passé à la modale pour qu'elle
  // puisse demander une confirmation explicite si l'admin déplace le badge.
  const currentlyHighlighted = rows.find((p) => p.highlighted === 1) ?? null;

  return (
    <>
      <div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
        {rows.map((p) => {
          // Plan per-seat (flex) : rendu read-only piloté par `pricing_tiers`,
          // jamais comme un plan flat (cf. mf_ask #128). Pas de bouton Modifier.
          if (isPerSeatPlan(p.code)) {
            return <PerSeatCard key={p.id} plan={p} tiers={pricingTiers} />;
          }
          // Plans flat : éditables sauf les legacy dépréciés (starter/pro/
          // enterprise) qui passent en read-only depuis la bascule per-seat
          // (mf_ask #134) — empêche de les ré-exposer au signup public.
          return (
            <FlatPlanCard
              key={p.id}
              plan={p}
              labelByCode={labelByCode}
              readOnly={!isPlanEditable(p.code)}
              onEdit={() => setEditing(p)}
            />
          );
        })}
      </div>

      <PlanEditModal
        plan={editing}
        featureCatalog={featureCatalog}
        currentlyHighlighted={currentlyHighlighted}
        open={editing !== null}
        onClose={() => setEditing(null)}
      />
    </>
  );
}

// Carte d'un plan flat (non per-seat). Éditable par défaut (bouton Modifier) ;
// `readOnly` pour les plans legacy dépréciés (starter/pro/enterprise) qu'on ne
// veut plus laisser ré-exposer au signup public depuis la bascule per-seat
// (mf_ask #134). En mode read-only : badge « Legacy », pas de bouton Modifier,
// et un encart explicatif.
function FlatPlanCard({
  plan: p,
  labelByCode,
  readOnly,
  onEdit,
}: {
  plan: PlanRow;
  labelByCode: Map<string, string>;
  readOnly: boolean;
  onEdit: () => void;
}) {
  const features = parseFeatures(p.features);
  return (
    <article
      className={`flex flex-col gap-3 rounded-lg border bg-surface p-5 ${
        readOnly ? "border-border-strong border-dashed" : "border-border"
      }`}
    >
      <header className="flex items-baseline justify-between gap-3">
        <div>
          <h2 className="text-lg font-semibold">{p.name}</h2>
          <p className="font-mono text-[11px] uppercase tracking-wider text-muted-foreground">
            {p.code}
          </p>
        </div>
        <div className="flex shrink-0 flex-col items-end gap-1">
          <Badge tone={p.visible ? "success" : "neutral"}>
            {p.visible ? "Visible" : "Caché"}
          </Badge>
          {readOnly && <Badge tone="neutral">Legacy</Badge>}
        </div>
      </header>

      {p.description && (
        <p className="text-xs text-muted-foreground">{p.description}</p>
      )}

      <div className="flex items-baseline gap-2">
        <span className="text-2xl font-semibold tabular-nums">
          {priceFmt.format(Number(p.monthly_price))}
        </span>
        <span className="text-xs text-muted-foreground">/mois</span>
        <span className="ml-auto text-xs text-muted-foreground tabular-nums">
          {priceFmt.format(Number(p.yearly_price))}/an
        </span>
      </div>

      <dl className="grid grid-cols-2 gap-2 border-t border-border pt-3 text-xs">
        <div>
          <dt className="text-muted-foreground">Techniciens</dt>
          <dd className="font-medium tabular-nums">
            {fmtQuota(p.max_technicians)}
          </dd>
        </div>
        <div title="Quota conservé en base mais plus appliqué depuis le pricing volume-only (2026-06-03) — les admins comptent dans le quota Techniciens">
          <dt className="text-muted-foreground">
            Administrateurs{" "}
            <span className="text-[10px] italic">(non appliqué)</span>
          </dt>
          <dd className="font-medium tabular-nums text-muted-foreground">
            {fmtQuota(p.max_admins)}
          </dd>
        </div>
        <div>
          <dt className="text-muted-foreground">Sites</dt>
          <dd className="font-medium tabular-nums">{fmtQuota(p.max_sites)}</dd>
        </div>
        <div>
          <dt className="text-muted-foreground">Machines</dt>
          <dd className="font-medium tabular-nums">
            {fmtQuota(p.max_machines)}
          </dd>
        </div>
        <div>
          <dt className="text-muted-foreground">Templates</dt>
          <dd className="font-medium tabular-nums">
            {fmtQuota(p.max_templates)}
          </dd>
        </div>
      </dl>

      {features.length > 0 && (
        <div className="flex flex-wrap gap-1.5 border-t border-border pt-3">
          {features.map((f) => (
            <span
              key={f}
              className="inline-block rounded border border-border bg-surface-2 px-2 py-0.5 text-[11px] text-foreground"
              title={f}
            >
              {labelByCode.get(f) ?? f}
            </span>
          ))}
        </div>
      )}

      {readOnly && (
        <div className="rounded-md border border-border bg-surface-2 px-3 py-2 text-[11px] leading-relaxed text-muted-foreground">
          🔒 Plan legacy déprécié depuis la bascule per-seat — conservé pour les
          tenants historiques mais non vendable. Édition désactivée pour éviter
          de le ré-exposer au signup public (suppression au Lot 6).
        </div>
      )}

      <footer className="mt-auto flex items-center justify-between gap-2 border-t border-border pt-3 text-xs">
        <span className="text-muted-foreground">
          <span className="font-semibold tabular-nums text-foreground">
            {p.active_subscriptions}
          </span>{" "}
          abonnement{p.active_subscriptions > 1 ? "s" : ""} actif
          {p.active_subscriptions > 1 ? "s" : ""}
        </span>
        {readOnly ? (
          <Button type="button" variant="ghost" size="sm" disabled>
            Read-only
          </Button>
        ) : (
          <Button type="button" variant="ghost" size="sm" onClick={onEdit}>
            Modifier
          </Button>
        )}
      </footer>
    </article>
  );
}

// Carte read-only pour un plan per-seat (flex). Le prix réel vient de la grille
// `pricing_tiers` (dégressive, par tranche de sièges), pas de monthly_price/
// yearly_price (= 0) ni des quotas max_* (= -1, illimité). On affiche donc la
// grille et on désactive toute édition : modifier ces colonnes côté panel n'a
// aucun effet côté app et tromperait l'admin (cf. mf_ask #128).
function PerSeatCard({ plan, tiers }: { plan: PlanRow; tiers: PricingTierRow[] }) {
  return (
    <article className="flex flex-col gap-3 rounded-lg border border-accent-ring/40 bg-surface p-5">
      <header className="flex items-baseline justify-between gap-3">
        <div>
          <h2 className="text-lg font-semibold">{plan.name}</h2>
          <p className="font-mono text-[11px] uppercase tracking-wider text-muted-foreground">
            {plan.code}
          </p>
        </div>
        <div className="flex shrink-0 flex-col items-end gap-1">
          <Badge tone={plan.visible ? "success" : "neutral"}>
            {plan.visible ? "Visible" : "Caché"}
          </Badge>
          <Badge tone="info">Per-seat</Badge>
        </div>
      </header>

      {plan.description && (
        <p className="text-xs text-muted-foreground">{plan.description}</p>
      )}

      <div className="rounded-md border border-border bg-surface-2 p-3">
        <p className="mb-2 text-[11px] font-medium uppercase tracking-wider text-muted-foreground">
          Tarif au siège actif (dégressif, HT)
        </p>
        {tiers.length === 0 ? (
          <p className="text-xs italic text-muted-foreground">
            Grille <code className="font-mono">pricing_tiers</code> indisponible
            (table non lisible ou vide).
          </p>
        ) : (
          <dl className="space-y-1 text-sm">
            {tiers.map((t) => (
              <div key={t.id} className="flex items-baseline justify-between gap-3">
                <dt className="text-muted-foreground">{fmtTierRange(t)}</dt>
                <dd className="font-semibold tabular-nums">
                  {priceFmt.format(t.unit_amount_cents / 100)}
                  <span className="text-xs font-normal text-muted-foreground">
                    {" "}
                    / siège / mois
                  </span>
                </dd>
              </div>
            ))}
          </dl>
        )}
        <p className="mt-2 border-t border-border pt-2 text-[10px] italic text-muted-foreground">
          Annuel = mensuel × 12 (sans remise), dérivé en code. Quotas illimités —
          le prix porte sur les sièges.
        </p>
      </div>

      <div className="rounded-md border border-border bg-surface-2 px-3 py-2 text-[11px] leading-relaxed text-muted-foreground">
        🔒 Édition désactivée — ce plan est piloté par la grille{" "}
        <code className="font-mono">pricing_tiers</code>, pas par les colonnes
        prix/quotas. Pour ajuster la grille, passer par{" "}
        <code className="font-mono">missioflow-app</code>.
      </div>

      <footer className="mt-auto flex items-center justify-between gap-2 border-t border-border pt-3 text-xs">
        <span className="text-muted-foreground">
          <span className="font-semibold tabular-nums text-foreground">
            {plan.active_subscriptions}
          </span>{" "}
          abonnement{plan.active_subscriptions > 1 ? "s" : ""} actif
          {plan.active_subscriptions > 1 ? "s" : ""}
        </span>
        <Button type="button" variant="ghost" size="sm" disabled>
          Read-only
        </Button>
      </footer>
    </article>
  );
}
