/**
 * Overview — the landing view.
 *
 * Leads with margin and idle capacity rather than deal counts, because those
 * are the numbers this business actually turns on. A CRM that opens on
 * "23 open opportunities" tells you nothing about whether you are making money.
 */
import { useQuery } from '@tanstack/react-query';
import { AlertTriangle, ArrowRight, Server, TrendingUp } from 'lucide-react';
import { Link } from 'react-router-dom';
import { compactNumber, get, money, percent, relativeTime } from '@/lib/api';
import { Badge, Button, Card, CardContent, CardHeader, CardTitle, EmptyState, Skeleton, Stat } from '@/components/ui';
import { usePageTitle } from '@/lib/title';

interface Dashboard {
  me: { name: string; teams: { team: string; role: string }[] };
  margin: {
    revenueCents: number;
    costCents: number;
    grossMarginCents: number;
    grossMarginPct: number | null;
    utilisation: number;
    idleGpuHours: number;
    committedGpuHours: number;
    allocatedGpuHours: number;
  };
  blocks: number;
  openDemandDeals: number;
  openSupplyDeals: number;
  idleAlerts: {
    commitmentId: string;
    name: string;
    gpuType: string;
    gpuCount: number;
    idleCostCents: number;
    utilisation: number;
    breakEvenPriceCents: number | null;
  }[];
  recentActivity: {
    id: string;
    type: string;
    subject: string | null;
    occurredAt: string;
  }[];
}

export function Overview() {
  usePageTitle('Overview');
  const { data, isLoading, error, refetch } = useQuery({
    queryKey: ['dashboard'],
    queryFn: () => get<Dashboard>('/api/dashboard'),
    // The book does not change second to second, but it does change while
    // someone is looking at it during a pipeline review.
    refetchInterval: 60_000,
  });

  if (isLoading) {
    return (
      <div className="grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
        {Array.from({ length: 4 }).map((_, i) => (
          <Skeleton key={i} className="h-28" />
        ))}
      </div>
    );
  }

  if (error || !data) {
    return (
      <Card>
        <CardContent className="flex flex-col items-center gap-4 pt-6">
          <EmptyState
            title="Could not load the overview"
            description={error instanceof Error ? error.message : 'Unknown error.'}
          />
          <Button variant="outline" onClick={() => void refetch()}>Try again</Button>
        </CardContent>
      </Card>
    );
  }

  const m = data.margin;
  const marginTone = m.grossMarginCents >= 0 ? 'positive' : 'danger';
  const firstName = data.me.name.split(' ')[0];
  const idleExposureCents = data.idleAlerts.reduce((sum, alert) => sum + alert.idleCostCents, 0);

  return (
    <div className="space-y-5 pb-[calc(5.5rem+var(--safe-bottom))] md:pb-0">
      <header>
        <h1 className="text-xl font-semibold tracking-tight sm:text-2xl">
          {greeting()}, {firstName}
        </h1>
        <p className="mt-1 text-sm text-muted">
          {data.blocks === 0
            ? 'No capacity commitments yet — margin appears once you record what you have bought.'
            : `${data.blocks} capacity commitment${data.blocks === 1 ? '' : 's'} on the book.`}
        </p>
      </header>

      <section className="grid grid-cols-2 gap-2 sm:gap-3 xl:grid-cols-4">
        <Stat
          label="Gross margin"
          value={money(m.grossMarginCents)}
          hint={`${percent(m.grossMarginPct, 1)} of revenue`}
          tone={marginTone}
        />
        <Stat
          label="Sold ratio"
          value={percent(m.utilisation, 1)}
          hint={`${compactNumber(m.allocatedGpuHours)} of ${compactNumber(m.committedGpuHours)} GPU-hrs sold`}
          tone={m.utilisation < 0.6 ? 'warning' : 'default'}
        />
        <Stat
          label="Idle capacity"
          value={`${compactNumber(m.idleGpuHours)} hrs`}
          hint="Bought and unsold"
          tone={m.idleGpuHours > 0 ? 'warning' : 'default'}
        />
        <Stat
          label="Open deals"
          value={data.openDemandDeals + data.openSupplyDeals}
          hint={`${data.openDemandDeals} demand · ${data.openSupplyDeals} supply`}
        />
      </section>

      {data.idleAlerts.length > 0 ? (
        <Card className="border-warning/30">
          <CardHeader className="flex-row items-start justify-between gap-3 space-y-0">
            <div className="flex min-w-0 items-start gap-2">
              <AlertTriangle className="mt-0.5 h-4 w-4 shrink-0 text-warning" aria-hidden />
              <div>
                <CardTitle className="text-base">Capacity you are paying for and not selling</CardTitle>
                <p className="mt-1 text-xs text-muted">Prioritized by idle cost exposure.</p>
              </div>
            </div>
            <Badge tone="warning" className="nums shrink-0">{money(idleExposureCents)}</Badge>
          </CardHeader>
          <CardContent className="space-y-2">
            {data.idleAlerts.map((alert) => (
              <div
                key={alert.commitmentId}
                className="flex flex-col gap-2 rounded-lg bg-surface-2 p-3 sm:flex-row sm:items-center sm:justify-between"
              >
                <div className="min-w-0">
                  <p className="truncate font-medium">{alert.name}</p>
                  <p className="text-xs text-muted">
                    {alert.gpuCount}× {alert.gpuType} · {percent(alert.utilisation)} sold
                    {/*
                      A zero break-even means the block's cost is already
                      covered, so any further sale is upside. Printing
                      "break even above $0.00" is technically true and reads
                      like a bug, so it is said in words instead.
                    */}
                    {alert.breakEvenPriceCents == null ? null : alert.breakEvenPriceCents > 0 ? (
                      <>
                        {' · '}break even above{' '}
                        <span className="nums">{money(alert.breakEvenPriceCents)}</span>/GPU-hr
                      </>
                    ) : (
                      <>{' · '}cost already covered — further sales are upside</>
                    )}
                  </p>
                </div>
                <div className="flex items-center gap-3 sm:justify-end">
                  <span className="nums whitespace-nowrap text-sm font-semibold text-warning">
                    {money(alert.idleCostCents)}
                  </span>
                  <Link
                    to="/capacity"
                    className="tap inline-flex min-h-11 items-center gap-1 rounded-lg px-3 text-sm font-medium text-accent-fg hover:bg-surface"
                    aria-label={`Match demand to ${alert.name}`}
                  >
                    Match
                    <ArrowRight className="h-3.5 w-3.5" aria-hidden />
                  </Link>
                </div>
              </div>
            ))}
          </CardContent>
        </Card>
      ) : null}

      <div className="grid gap-4 lg:grid-cols-2">
        <Card>
          <CardHeader>
            <CardTitle className="text-base">The book</CardTitle>
          </CardHeader>
          <CardContent className="space-y-2 text-sm">
            <Row label="Revenue" value={money(m.revenueCents)} />
            <Row label="Cost of committed capacity" value={money(m.costCents)} />
            <div className="border-t border-border pt-2">
              <Row
                label="Gross margin"
                value={money(m.grossMarginCents)}
                emphasis
                tone={marginTone}
              />
            </div>
            <p className="pt-2 text-xs leading-relaxed text-muted">
              Cost is charged against the full commitment, not only the hours that sold —
              unsold hours are already paid for.
            </p>
          </CardContent>
        </Card>

        <Card>
          <CardHeader>
            <CardTitle className="text-base">Recent activity</CardTitle>
          </CardHeader>
          <CardContent>
            {data.recentActivity.length === 0 ? (
              <p className="py-6 text-center text-sm text-muted">Nothing logged yet.</p>
            ) : (
              <ul className="space-y-2.5">
                {data.recentActivity.slice(0, 8).map((activity) => (
                  <li key={activity.id} className="flex items-start gap-2 text-sm">
                    <Badge tone="neutral" className="mt-0.5 shrink-0">
                      {activity.type.replace('_', ' ')}
                    </Badge>
                    <span className="min-w-0 flex-1 truncate">{activity.subject ?? '—'}</span>
                    <span className="shrink-0 text-xs text-muted">
                      {relativeTime(activity.occurredAt)}
                    </span>
                  </li>
                ))}
              </ul>
            )}
          </CardContent>
        </Card>
      </div>

      {data.blocks === 0 ? (
        <Card>
          <CardContent className="pt-5">
            <EmptyState
              icon={<Server className="h-8 w-8" />}
              title="No capacity on the book yet"
              description="Record a capacity commitment — what you bought, at what cost, over what term — and margin, utilisation and idle alerts all follow from it."
            />
          </CardContent>
        </Card>
      ) : null}
    </div>
  );
}

function Row({
  label,
  value,
  emphasis,
  tone,
}: {
  label: string;
  value: string;
  emphasis?: boolean;
  tone?: 'positive' | 'danger';
}) {
  return (
    <div className="flex items-baseline justify-between gap-3">
      <span className={emphasis ? 'font-medium' : 'text-muted'}>{label}</span>
      <span
        className={[
          'nums tabular-nums',
          emphasis ? 'text-base font-semibold' : '',
          tone === 'positive' ? 'text-positive' : tone === 'danger' ? 'text-danger' : '',
        ].join(' ')}
      >
        {value}
      </span>
    </div>
  );
}

function greeting(): string {
  const hour = new Date().getHours();
  if (hour < 12) return 'Good morning';
  if (hour < 18) return 'Good afternoon';
  return 'Good evening';
}
