/**
 * The pipeline boards, for both sides of the market.
 *
 * A column-per-stage board on desktop; on a phone, a stage picker and a single
 * column. A horizontally scrolling eight-column board on a 390px screen is
 * technically responsive and practically unusable — you cannot see where a
 * card is going, which is the entire point of a board.
 */
import { useMemo, useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import type { PermissionGrant } from '@pig/core';
import { Pencil, Plus } from 'lucide-react';
import { get, money, relativeTime } from '@/lib/api';
import { Badge, Button, Card, EmptyState, Skeleton } from '@/components/ui';
import { usePageTitle } from '@/lib/title';
import { can } from '@/lib/permissions';
import {
  DemandDealSheet,
  SupplyDealSheet,
  type DemandDealRecord,
  type SupplyDealRecord,
} from '@/components/RecordSheets';

interface Board<T> {
  stages: string[];
  deals: { deal: T; accountName: string | null }[];
}

const STAGE_LABELS: Record<string, string> = {
  qualification: 'Qualification',
  legal: 'Legal',
  scoping: 'Scoping',
  proposal: 'Proposal',
  procurement: 'Procurement',
  poc: 'POC',
  deployment: 'Deployment',
  expansion: 'Expansion',
  closed_won: 'Closed won',
  closed_lost: 'Closed lost',
  sourced: 'Sourced',
  qualifying: 'Qualifying',
  technical_diligence: 'Technical diligence',
  financial_diligence: 'Financial diligence',
  pricing: 'Pricing',
  contracting: 'Contracting',
  onboarding: 'Onboarding',
  live: 'Live',
  renewal: 'Renewal',
  churned: 'Churned',
  rejected: 'Rejected',
};

export function DemandPipeline() {
  return (
    <PipelineBoard<DemandDealRecord>
      title="Demand"
      subtitle="Selling compute and post-training. Note that legal sits early — paper gates the deal rather than closing it."
      endpoint="/api/deals/demand"
      team="demand"
      renderSheet={({ open, onOpenChange, record }) => <DemandDealSheet open={open} onOpenChange={onOpenChange} record={record} />}
      renderCard={(deal, accountName) => (
        <>
          <p className="truncate font-medium">{deal.name}</p>
          <p className="truncate text-xs text-muted">{accountName ?? 'No account'}</p>
          <div className="mt-2 flex flex-wrap items-center gap-1.5">
            {deal.acvCents ? (
              <span className="nums text-sm font-semibold">{money(deal.acvCents)}</span>
            ) : null}
            <Badge tone="neutral">{deal.productLine.replace(/_/g, ' ')}</Badge>
            {/* Contract state is surfaced on the card because shipping capacity
                without executed paper is the mistake this pipeline prevents. */}
            {deal.msaExecuted ? <Badge tone="positive">MSA</Badge> : null}
            {deal.dpaExecuted ? <Badge tone="positive">DPA</Badge> : null}
          </div>
        </>
      )}
    />
  );
}

export function SupplyPipeline() {
  return (
    <PipelineBoard<SupplyDealRecord>
      title="Supply"
      subtitle="Sourcing GPU capacity. Technical and financial diligence are separate gates — accepting capacity is a two-key decision."
      endpoint="/api/deals/supply"
      team="supply"
      renderSheet={({ open, onOpenChange, record }) => <SupplyDealSheet open={open} onOpenChange={onOpenChange} record={record} />}
      renderCard={(deal, accountName) => (
        <>
          <p className="truncate font-medium">{deal.name}</p>
          <p className="truncate text-xs text-muted">{accountName ?? 'No account'}</p>
          <div className="mt-2 flex flex-wrap items-center gap-1.5">
            {deal.gpuCount && deal.gpuType ? (
              <Badge tone="accent">
                {deal.gpuCount}× {deal.gpuType}
              </Badge>
            ) : null}
            {deal.targetCostPerGpuHourCents ? (
              <span className="nums text-xs text-muted">
                {money(deal.targetCostPerGpuHourCents)}/hr target
              </span>
            ) : null}
          </div>
        </>
      )}
    />
  );
}

function PipelineBoard<T extends { id: string; stage: string; updatedAt: string }>({
  title,
  subtitle,
  endpoint,
  team,
  renderCard,
  renderSheet,
}: {
  title: string;
  subtitle: string;
  endpoint: string;
  team: 'supply' | 'demand';
  renderCard: (deal: T, accountName: string | null) => React.ReactNode;
  renderSheet: (props: { open: boolean; onOpenChange(open: boolean): void; record?: T }) => React.ReactNode;
}) {
  usePageTitle(title);

  const { data, isLoading } = useQuery({
    queryKey: [endpoint],
    queryFn: () => get<Board<T>>(endpoint),
  });
  const { data: me } = useQuery({
    queryKey: ['me'],
    queryFn: () => get<{ permissions: PermissionGrant[] }>('/api/me'),
  });
  const writable = can(me, 'deal:write', team);
  const [sheet, setSheet] = useState<{ open: boolean; record?: T }>({ open: false });

  const [activeStage, setActiveStage] = useState<string | null>(null);

  const byStage = useMemo(() => {
    const map = new Map<string, { deal: T; accountName: string | null }[]>();
    for (const stage of data?.stages ?? []) map.set(stage, []);
    for (const row of data?.deals ?? []) {
      map.get(row.deal.stage)?.push(row);
    }
    return map;
  }, [data]);

  if (isLoading) return <Skeleton className="h-96" />;

  if (!data || data.deals.length === 0) {
    return (
      <div className="space-y-5">
        <Header title={title} subtitle={subtitle} writable={writable} onCreate={() => setSheet({ open: true })} />
        <Card>
          <EmptyState
            title={`No ${title.toLowerCase()} deals yet`}
            description="Deals appear here once created. Stages follow how this market actually operates rather than a generic sales funnel."
            action={<Button variant="primary" disabled={!writable} onClick={() => setSheet({ open: true })}><Plus aria-hidden />New {title.toLowerCase()} deal</Button>}
          />
        </Card>
        {renderSheet({ open: sheet.open, onOpenChange: (open) => setSheet((state) => ({ ...state, open })), record: sheet.record })}
      </div>
    );
  }

  const stages = data.stages;
  const currentStage = activeStage ?? stages[0]!;

  return (
    <div className="space-y-5">
      <Header title={title} subtitle={subtitle} writable={writable} onCreate={() => setSheet({ open: true })} />

      {/* Phone: pick one stage. The chips scroll; the board does not. */}
      <div className="lg:hidden">
        <div className="scroll-x -mx-4 flex gap-2 px-4 pb-1">
          {stages.map((stage) => {
            const count = byStage.get(stage)?.length ?? 0;
            return (
              <button
                key={stage}
                onClick={() => setActiveStage(stage)}
                className={[
                  'tap shrink-0 rounded-full px-3.5 text-sm font-medium transition-colors',
                  stage === currentStage
                    ? 'bg-primary text-accent-on'
                    : 'bg-surface-2 text-muted',
                ].join(' ')}
              >
                {STAGE_LABELS[stage] ?? stage}
                <span className="ml-1.5 opacity-70">{count}</span>
              </button>
            );
          })}
        </div>
        <div className="mt-3 space-y-2">
          {(byStage.get(currentStage) ?? []).map((row) => (
            <DealCard key={row.deal.id} row={row} renderCard={renderCard} writable={writable} onEdit={() => setSheet({ open: true, record: row.deal })} />
          ))}
          {(byStage.get(currentStage) ?? []).length === 0 ? (
            <p className="py-8 text-center text-sm text-muted">
              Nothing in {STAGE_LABELS[currentStage] ?? currentStage}.
            </p>
          ) : null}
        </div>
      </div>

      {/* Desktop: the full board, scrolling horizontally within its own pane
          so the page itself never scrolls sideways. */}
      <div className="scroll-x hidden lg:block">
        <div className="flex gap-3 pb-2">
          {stages.map((stage) => {
            const rows = byStage.get(stage) ?? [];
            return (
              <section key={stage} className="w-72 shrink-0">
                <div className="mb-2 flex items-center justify-between px-1">
                  <h2 className="text-sm font-semibold">{STAGE_LABELS[stage] ?? stage}</h2>
                  <span className="nums text-xs text-muted">{rows.length}</span>
                </div>
                <div className="space-y-2">
                  {rows.map((row) => (
                    <DealCard key={row.deal.id} row={row} renderCard={renderCard} writable={writable} onEdit={() => setSheet({ open: true, record: row.deal })} />
                  ))}
                </div>
              </section>
            );
          })}
        </div>
      </div>
      {renderSheet({ open: sheet.open, onOpenChange: (open) => setSheet((state) => ({ ...state, open })), record: sheet.record })}
    </div>
  );
}

function DealCard<T extends { id: string; updatedAt: string }>({
  row,
  renderCard,
  writable,
  onEdit,
}: {
  row: { deal: T; accountName: string | null };
  renderCard: (deal: T, accountName: string | null) => React.ReactNode;
  writable: boolean;
  onEdit(): void;
}) {
  return (
    <article className="card relative p-3 pr-12">
      <Button size="icon" variant="ghost" className="absolute right-1 top-1" disabled={!writable} onClick={onEdit} title="Edit deal"><Pencil aria-hidden /><span className="sr-only">Edit deal</span></Button>
      {renderCard(row.deal, row.accountName)}
      <p className="mt-2 text-[11px] text-muted">{relativeTime(row.deal.updatedAt)}</p>
    </article>
  );
}

function Header({ title, subtitle, writable, onCreate }: { title: string; subtitle: string; writable: boolean; onCreate(): void }) {
  return (
    <header className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
      <div><h1 className="text-xl font-semibold tracking-tight sm:text-2xl">{title}</h1><p className="mt-1 max-w-2xl text-sm text-muted">{subtitle}</p></div>
      <Button variant="primary" disabled={!writable} onClick={onCreate}><Plus aria-hidden />New deal</Button>
    </header>
  );
}
