'use client';

import { useQuery } from '@tanstack/react-query';
import { AlertTriangle, Info } from 'lucide-react';

import { apiFetch } from '@/lib/api/client';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { Skeleton } from '@/components/ui/skeleton';
import { PIPELINE_STAGES, STAGE_WEIGHTS, stageLabel } from '@/lib/constants';
import { rangeToSlug, type DateRange } from '@/lib/analytics/range';
import { formatCurrency } from '@/lib/utils/currency';
import { cn } from '@/lib/utils';

interface KpiResponse {
  pipelineValue: number;
  pipelineValueCurrency: string;
  activeInterests: number;
}

interface StageRow {
  stage: string;
  count: number;
  grossValue: number;
  weightedValue: number;
  weight: number;
  dealsMissingPrice: number;
}

interface ForecastResponse {
  totalGrossValue: number;
  totalWeightedValue: number;
  stageBreakdown: StageRow[];
  weightsSource: 'db' | 'default';
}

// Same brand-coloured family the pipeline-funnel chart uses so the two
// surfaces feel anchored to the same palette.
const STAGE_BAR_CLASS: Record<string, string> = {
  enquiry: 'bg-slate-300',
  qualified: 'bg-brand-200',
  nurturing: 'bg-brand-300',
  eoi: 'bg-brand-400',
  reservation: 'bg-amber-400',
  deposit_paid: 'bg-orange-400',
  contract: 'bg-success/70',
};

/**
 * Headline pipeline value plus a per-stage breakdown showing gross
 * value, deal count, and the weighted forecast (gross × stage close-
 * probability). Replaces the single-number KPI: leadership can now see
 * how much of the headline number is near-close vs speculative.
 *
 * Pulls from two endpoints: `/kpis` for the gross headline + currency
 * and `/forecast` for the weighted breakdown. Both share cache entries
 * with other widgets so this is mostly free.
 */
export function PipelineValueTile({ range }: { range?: DateRange } = {}) {
  // Range query-string is keyed on the slug ('7d' / 'custom-2026-01-01...').
  // When range is undefined, the tile falls back to the "all active deals"
  // snapshot - preserves the old behaviour for callers that don't yet
  // thread range through.
  const slug = range ? rangeToSlug(range) : null;
  const qs = slug ? `?range=${encodeURIComponent(slug)}` : '';
  const kpis = useQuery<KpiResponse>({
    queryKey: ['dashboard', 'kpis', slug],
    queryFn: () => apiFetch<KpiResponse>(`/api/v1/dashboard/kpis${qs}`),
    staleTime: 60_000,
  });
  const forecast = useQuery<ForecastResponse>({
    queryKey: ['dashboard', 'forecast', slug],
    queryFn: () => apiFetch<ForecastResponse>(`/api/v1/dashboard/forecast${qs}`),
    staleTime: 60_000,
  });

  const isLoading = kpis.isLoading || forecast.isLoading;
  const currency = kpis.data?.pipelineValueCurrency ?? 'USD';
  const grossTotal = kpis.data?.pipelineValue ?? 0;
  const weightedTotal = forecast.data?.totalWeightedValue ?? 0;
  const activeDeals = kpis.data?.activeInterests ?? 0;
  const activeStages = (forecast.data?.stageBreakdown ?? []).filter((s) => s.count > 0);
  const stageMax = activeStages.reduce((m, s) => Math.max(m, s.grossValue), 0) || 1;

  const fmt = (v: number) => formatCurrency(v, currency, { maxFractionDigits: 0 });
  // Compact variant for the per-stage cell on narrow viewports — $3,528,000
  // overflows the right column at 375px otherwise. Falls back to the full
  // format at sm+ where there's room.
  const fmtCompact = (v: number) => {
    try {
      return new Intl.NumberFormat(undefined, {
        style: 'currency',
        currency: currency || 'USD',
        notation: 'compact',
        maximumFractionDigits: 1,
      }).format(v);
    } catch {
      return fmt(v);
    }
  };

  return (
    <Card>
      <CardHeader>
        <CardTitle className="text-base">Pipeline value</CardTitle>
        <CardDescription className="flex items-center gap-1.5">
          <span>
            {activeDeals > 0
              ? `${activeDeals} active deal${activeDeals === 1 ? '' : 's'} · weighted by stage close-probability`
              : 'Gross berth value across active deals, with weighted forecast.'}
          </span>
          <Popover>
            <PopoverTrigger
              type="button"
              aria-label="How does the weighted forecast work?"
              className="inline-flex size-4 shrink-0 items-center justify-center rounded-full text-muted-foreground hover:bg-muted hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-400"
            >
              <Info className="size-3.5" aria-hidden />
            </PopoverTrigger>
            <PopoverContent align="start" className="w-80 text-xs leading-relaxed">
              <p className="font-semibold text-foreground">How the weighted forecast works</p>
              <p className="mt-2 text-muted-foreground">
                Each pipeline stage has a close-probability - how likely a deal at that stage is to
                actually close. Multiplying the berth price by the stage weight gives an{' '}
                <strong>expected</strong> value for that deal. Summing across every active deal
                yields the weighted forecast - a defensible &ldquo;what will likely land&rdquo;
                number, vs the gross which assumes every deal closes at full value.
              </p>
              <div className="mt-3 grid grid-cols-[1fr_auto] gap-x-3 gap-y-1 rounded-md bg-muted/50 p-2.5 text-xs">
                {PIPELINE_STAGES.map((s) => {
                  const dbWeight = forecast.data?.stageBreakdown.find((r) => r.stage === s)?.weight;
                  const weight = dbWeight ?? STAGE_WEIGHTS[s];
                  return (
                    <div key={s} className="contents">
                      <span className="text-muted-foreground">{stageLabel(s)}</span>
                      <span className="text-right font-medium tabular-nums text-foreground">
                        {Math.round(weight * 100)}%
                      </span>
                    </div>
                  );
                })}
              </div>
              <p className="mt-3 text-xs text-muted-foreground">
                {forecast.data?.weightsSource === 'db'
                  ? 'Using per-port weights (admins tune these in Settings → Pipeline).'
                  : 'Using system defaults. Admins can override per port in Settings → Pipeline.'}
              </p>
            </PopoverContent>
          </Popover>
        </CardDescription>
      </CardHeader>
      <CardContent className="space-y-4">
        {/* ── Headline numbers ─────────────────────────────────────── */}
        <div className="flex items-end justify-between gap-4">
          <div className="min-w-0">
            <p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
              Gross
            </p>
            {isLoading ? (
              <Skeleton className="mt-1 h-7 w-28" aria-hidden />
            ) : (
              <p
                className="truncate text-2xl font-bold leading-tight text-foreground"
                title={formatCurrency(grossTotal, currency)}
              >
                {fmt(grossTotal)}
              </p>
            )}
          </div>
          <div className="text-right">
            <p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
              Weighted forecast
            </p>
            {isLoading ? (
              <Skeleton className="ml-auto mt-1 h-6 w-24" aria-hidden />
            ) : (
              <p
                className="text-lg font-semibold leading-tight text-foreground tabular-nums"
                title={formatCurrency(weightedTotal, currency)}
              >
                {fmt(weightedTotal)}
              </p>
            )}
          </div>
        </div>

        {/* ── Per-stage breakdown ─────────────────────────────────── */}
        {isLoading ? (
          <div className="space-y-1.5">
            {Array.from({ length: 4 }).map((_, i) => (
              <Skeleton key={i} className="h-7 w-full" aria-hidden />
            ))}
          </div>
        ) : activeStages.length === 0 ? (
          <p className="text-sm text-muted-foreground">No active deals with linked berths yet.</p>
        ) : (
          <ul className="space-y-0.5">
            {activeStages.map((s) => {
              const widthPct = Math.max(6, Math.round((s.grossValue / stageMax) * 100));
              return (
                <li
                  key={s.stage}
                  className="grid grid-cols-[1fr_auto] items-center gap-x-3 gap-y-0.5 py-1"
                >
                  <div className="min-w-0">
                    <p className="truncate text-sm font-medium text-foreground">
                      {stageLabel(s.stage)}
                    </p>
                    <div className="mt-1 flex h-1 w-full overflow-hidden rounded-full bg-muted">
                      <span
                        aria-hidden
                        className={cn(
                          'h-full rounded-full',
                          STAGE_BAR_CLASS[s.stage] ?? 'bg-brand-400',
                        )}
                        style={{ width: `${widthPct}%` }}
                      />
                    </div>
                  </div>
                  <div className="text-right">
                    <p className="text-sm font-semibold text-foreground tabular-nums">
                      <span className="sm:hidden">{fmtCompact(s.grossValue)}</span>
                      <span className="hidden sm:inline">{fmt(s.grossValue)}</span>
                    </p>
                    <p className="text-xs text-muted-foreground tabular-nums">
                      {s.count} {s.count === 1 ? 'deal' : 'deals'} · {Math.round(s.weight * 100)}%
                    </p>
                    {s.dealsMissingPrice > 0 ? (
                      <p
                        className="mt-0.5 inline-flex items-center gap-1 text-xs font-medium text-warning"
                        title={`${s.dealsMissingPrice} of ${s.count} ${s.count === 1 ? 'deal has' : 'deals have'} a berth with no price set  -  gross is undercounted here.`}
                      >
                        <AlertTriangle className="size-3" aria-hidden />
                        {s.dealsMissingPrice === s.count
                          ? 'berth price missing'
                          : `${s.dealsMissingPrice} of ${s.count} missing price`}
                      </p>
                    ) : null}
                  </div>
                </li>
              );
            })}
          </ul>
        )}

        {forecast.data?.weightsSource === 'default' ? (
          <p className="text-xs text-muted-foreground">
            Using default stage weights. Tune them in Settings → Pipeline.
          </p>
        ) : null}
      </CardContent>
    </Card>
  );
}
