import { useMemo, useState } from 'react';
import { CheckCircle2, ChevronDown, HelpCircle, XCircle } from 'lucide-react';
import { VERIFY_TOLERANCE, verifyEpisode } from '@/lib/demo-kit/verify';
import type { AnyDemoModule } from '@/lib/demo-kit/registry';
import type { DemoEpisode } from '@/lib/demo-kit/types';
import { cn } from '@/lib/utils';
import { DASH, formatDelta, formatNumber, formatOrDash } from './format';

export interface VerifyBadgeProps {
  demo: AnyDemoModule;
  episode: DemoEpisode;
  className?: string;
  /** Open the receipt on load. The sceptic we wrote this for opens it anyway. */
  defaultOpen?: boolean;
}

/**
 * The receipt.
 *
 * This object exists for one person: the engineer sitting next to the CEO who
 * assumes the numbers on a vendor's demo page are hard-coded. It re-runs the
 * recorded trace through the demo's own TypeScript grader, in the visitor's
 * browser, and prints the comparison — including the delta to seven decimals,
 * because a comparison without a delta is an assertion.
 *
 * It must be allowed to FAIL loudly. A badge that degrades to "verified" when
 * it could not check anything is worse than no badge: it teaches the sceptic
 * that the whole thing is decoration. The three states come straight from
 * `verifyEpisode`, and `unverifiable` is never dressed up as either of the
 * other two.
 */
export function VerifyBadge({ demo, episode, className, defaultOpen = false }: VerifyBadgeProps) {
  const [open, setOpen] = useState(defaultOpen);
  const result = useMemo(() => verifyEpisode(demo, episode), [demo, episode]);

  if (result.status === 'unverifiable') {
    return (
      <section
        aria-label="Verification"
        className={cn('card bg-surface-2 p-3', className)}
      >
        <p className="flex items-start gap-2 text-sm">
          <HelpCircle className="mt-0.5 size-4 shrink-0 text-muted" aria-hidden="true" />
          <span>
            <span className="font-semibold">Unverifiable in your browser.</span>{' '}
            <span className="text-muted">
              {result.reason ?? 'This run cannot be re-computed here.'}
            </span>
          </span>
        </p>
        {result.recorded !== null ? (
          <p className="nums mt-1.5 pl-6 font-mono text-xs text-muted">
            Recorded {formatOrDash(result.recorded)} · recomputed {DASH} · Δ {DASH}
          </p>
        ) : null}
      </section>
    );
  }

  const matched = result.status === 'match';

  return (
    <section
      aria-label="Verification"
      className={cn('card overflow-hidden', matched ? 'border-positive/40' : 'border-danger', className)}
    >
      <div className={cn('p-3', matched ? 'bg-positive/10' : 'bg-danger/10')}>
        <p className="flex items-start gap-2 text-sm leading-relaxed">
          {matched ? (
            <CheckCircle2 className="mt-0.5 size-4 shrink-0 text-positive" aria-hidden="true" />
          ) : (
            <XCircle className="mt-0.5 size-4 shrink-0 text-danger" aria-hidden="true" />
          )}
          <span>
            {matched ? (
              <>
                <span className="font-semibold text-positive">Verified in your browser</span>{' '}
                <span className="text-fg">
                  — re-ran every move through the TypeScript engine and rescored.
                </span>
              </>
            ) : (
              <>
                <span className="font-semibold text-danger">
                  {result.culprit
                    ? `Mismatch on "${result.culprit.label}"`
                    : 'Mismatch against the recorded score'}
                </span>{' '}
                <span className="text-fg">
                  — the browser re-run disagrees with the published number. Trust the source in
                  the repository, not this page.
                </span>
              </>
            )}
          </span>
        </p>
        <p className="nums mt-1.5 pl-6 font-mono text-xs text-muted">
          Recomputed {formatOrDash(result.recomputed)} · recorded {formatOrDash(result.recorded)} ·
          Δ {result.delta === null ? DASH : formatDelta(result.delta)}
        </p>
      </div>

      <button
        type="button"
        onClick={() => setOpen((was) => !was)}
        aria-expanded={open}
        className="tap flex w-full items-center gap-1.5 border-t border-border px-3 text-left text-xs font-medium text-muted transition-colors duration-2 ease-enter hover:bg-surface-2 hover:text-fg"
      >
        <ChevronDown
          className={cn('size-4 transition-transform duration-2 ease-enter', open && 'rotate-180')}
          aria-hidden="true"
        />
        {open ? 'Hide the component-by-component receipt' : 'Show the component-by-component receipt'}
      </button>

      {open ? (
        <div className="border-t border-border">
          <div className="overflow-x-auto">
            <table className="nums w-full border-collapse font-mono text-xs">
              <thead>
                <tr className="text-left text-muted">
                  <th scope="col" className="px-3 py-1.5 font-medium">
                    Component
                  </th>
                  <th scope="col" className="px-2 py-1.5 text-right font-medium">
                    Recorded
                  </th>
                  <th scope="col" className="px-2 py-1.5 text-right font-medium">
                    Recomputed
                  </th>
                  <th scope="col" className="px-3 py-1.5 text-right font-medium">
                    Δ
                  </th>
                </tr>
              </thead>
              <tbody className="divide-y divide-border">
                {result.components.map((row) => {
                  const bad = row.delta !== null && Math.abs(row.delta) > VERIFY_TOLERANCE;
                  return (
                    <tr key={row.key} className={cn(bad && 'bg-danger/10')}>
                      <th scope="row" className="whitespace-nowrap px-3 py-1.5 text-left font-normal">
                        {row.label}
                      </th>
                      <td className="px-2 py-1.5 text-right">
                        {row.recorded === null ? DASH : formatNumber(row.recorded, 6)}
                      </td>
                      <td className="px-2 py-1.5 text-right">
                        {row.recomputed === null ? DASH : formatNumber(row.recomputed, 6)}
                      </td>
                      <td className={cn('px-3 py-1.5 text-right', bad ? 'text-danger' : 'text-muted')}>
                        {/* An em dash, not 0.0000000: one side was never scored,
                            so there is no difference to report. */}
                        {row.delta === null ? DASH : formatDelta(row.delta)}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
          <p className="px-3 py-2 text-[11px] leading-relaxed text-muted">
            Tolerance {VERIFY_TOLERANCE.toExponential()}. The recorded numbers came out of Python
            and these came out of JavaScript; both are IEEE-754 doubles summing the same terms in
            a different order, so the comparison is made within a tolerance rather than demanding
            bit-identical floats.
          </p>
        </div>
      ) : null}
    </section>
  );
}
