"use client";

import { useMemo, useState } from "react";
import { clsx } from "clsx";
import {
  compareEstimateVersions,
  type VersionCompareInput,
  type ChapterSubtotal,
  type ResourceSnapshotDiff,
  type ScopeItemDiff,
} from "@capakraken/engine";
import type { EstimateVersionView } from "~/components/estimates/EstimateWorkspace.types.js";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
import { formatMoney } from "~/lib/format.js";

function formatDelta(value: number, formatter: (v: number) => string) {
  const prefix = value > 0 ? "+" : "";
  return `${prefix}${formatter(value)}`;
}

function formatHoursDelta(delta: number) {
  const prefix = delta > 0 ? "+" : "";
  return `${prefix}${delta.toFixed(1)} h`;
}

function versionToInput(v: EstimateVersionView): VersionCompareInput {
  return {
    label: v.label ?? null,
    versionNumber: v.versionNumber,
    demandLines: v.demandLines.map((l) => ({
      id: l.id,
      name: l.name,
      hours: l.hours,
      costRateCents: l.costRateCents,
      billRateCents: l.billRateCents,
      costTotalCents: l.costTotalCents,
      priceTotalCents: l.priceTotalCents,
      ...(l.chapter !== undefined ? { chapter: l.chapter } : {}),
      lineType: l.lineType,
    })),
    assumptions: v.assumptions.map((a) => ({
      key: a.key,
      label: a.label,
      value: a.value,
    })),
    scopeItems: v.scopeItems.map((s) => ({
      id: s.id,
      name: s.name,
      sequenceNo: s.sequenceNo,
      scopeType: s.scopeType,
      ...(s.packageCode !== undefined ? { packageCode: s.packageCode } : {}),
      ...(s.description !== undefined ? { description: s.description } : {}),
      ...(s.frameCount !== undefined ? { frameCount: s.frameCount } : {}),
      ...(s.itemCount !== undefined ? { itemCount: s.itemCount } : {}),
    })),
    resourceSnapshots: v.resourceSnapshots.map((r) => ({
      id: r.id,
      ...(r.resourceId !== undefined ? { resourceId: r.resourceId } : {}),
      displayName: r.displayName,
      ...(r.chapter !== undefined ? { chapter: r.chapter } : {}),
      currency: r.currency,
      lcrCents: r.lcrCents,
      ucrCents: r.ucrCents,
      ...(r.location !== undefined ? { location: r.location } : {}),
      ...(r.level !== undefined ? { level: r.level } : {}),
    })),
  };
}

const STATUS_ROW_STYLES = {
  added: "bg-emerald-50",
  removed: "bg-red-50",
  changed: "bg-amber-50",
  unchanged: "",
} as const;

const STATUS_BADGE_STYLES = {
  added: "bg-emerald-100 text-emerald-700",
  removed: "bg-red-100 text-red-700",
  changed: "bg-amber-100 text-amber-700",
  unchanged: "bg-gray-100 text-gray-500",
} as const;

export function VersionCompare({ versions }: { versions: EstimateVersionView[] }) {
  const sorted = useMemo(
    () => [...versions].sort((a, b) => b.versionNumber - a.versionNumber),
    [versions],
  );

  const [aId, setAId] = useState<string>(sorted[1]?.id ?? sorted[0]?.id ?? "");
  const [bId, setBId] = useState<string>(sorted[0]?.id ?? "");
  const [hideUnchanged, setHideUnchanged] = useState(false);

  const versionA = sorted.find((v) => v.id === aId);
  const versionB = sorted.find((v) => v.id === bId);

  const diff = useMemo(() => {
    if (!versionA || !versionB || versionA.id === versionB.id) return null;
    return compareEstimateVersions(versionToInput(versionA), versionToInput(versionB));
  }, [versionA, versionB]);

  if (sorted.length < 2) {
    return (
      <div className="rounded-3xl border border-gray-200 bg-gray-50 p-8 text-center text-sm text-gray-500">
        At least two versions are required to compare.
      </div>
    );
  }

  const filteredDemandDiffs = diff
    ? hideUnchanged
      ? diff.demandLineDiffs.filter((d) => d.status !== "unchanged")
      : diff.demandLineDiffs
    : [];

  const filteredAssumptionDiffs = diff
    ? hideUnchanged
      ? diff.assumptionDiffs.filter((d) => d.status !== "unchanged")
      : diff.assumptionDiffs
    : [];

  const filteredScopeDiffs = diff
    ? hideUnchanged
      ? diff.scopeItemDiffs.filter((d) => d.status !== "unchanged")
      : diff.scopeItemDiffs
    : [];

  const filteredResourceDiffs = diff
    ? hideUnchanged
      ? diff.resourceSnapshotDiffs.filter((d) => d.status !== "unchanged")
      : diff.resourceSnapshotDiffs
    : [];

  return (
    <div className="space-y-6">
      {/* Version selectors */}
      <div className="rounded-3xl border border-gray-200 bg-white p-5 shadow-sm">
        <h3 className="mb-4 text-base font-semibold text-gray-900">Compare versions <InfoTooltip content="Select two version snapshots to see what changed in demand lines, scope, assumptions, and resource rates between them." /></h3>
        <div className="flex flex-wrap items-end gap-4">
          <label className="block">
            <span className="mb-1 block text-xs font-medium text-gray-500 uppercase tracking-wider">Base (A) <InfoTooltip content="The older or reference version to compare from." /></span>
            <select
              value={aId}
              onChange={(e) => setAId(e.target.value)}
              className="rounded-2xl border border-gray-300 bg-gray-50 px-3 py-2 text-sm text-gray-900 focus:border-brand-400 focus:outline-none focus:ring-1 focus:ring-brand-400"
            >
              {sorted.map((v) => (
                <option key={v.id} value={v.id}>
                  v{v.versionNumber} {v.label ? `\u2014 ${v.label}` : ""} ({v.status})
                </option>
              ))}
            </select>
          </label>

          <span className="pb-2 text-sm text-gray-400">vs</span>

          <label className="block">
            <span className="mb-1 block text-xs font-medium text-gray-500 uppercase tracking-wider">Compare (B) <InfoTooltip content="The newer or target version to compare against." /></span>
            <select
              value={bId}
              onChange={(e) => setBId(e.target.value)}
              className="rounded-2xl border border-gray-300 bg-gray-50 px-3 py-2 text-sm text-gray-900 focus:border-brand-400 focus:outline-none focus:ring-1 focus:ring-brand-400"
            >
              {sorted.map((v) => (
                <option key={v.id} value={v.id}>
                  v{v.versionNumber} {v.label ? `\u2014 ${v.label}` : ""} ({v.status})
                </option>
              ))}
            </select>
          </label>

          <label className="flex items-center gap-2 pb-2 text-sm text-gray-600">
            <input
              type="checkbox"
              checked={hideUnchanged}
              onChange={(e) => setHideUnchanged(e.target.checked)}
              className="rounded border-gray-300"
            />
            Hide unchanged
          </label>
        </div>

        {aId === bId && (
          <p className="mt-3 text-sm text-amber-600">Select two different versions to compare.</p>
        )}
      </div>

      {diff && (
        <>
          {/* Summary cards */}
          <div className="grid grid-cols-2 gap-4 sm:grid-cols-4 lg:grid-cols-8">
            <SummaryCard
              label="Hours"
              value={formatHoursDelta(diff.summary.totalHoursDelta)}
              positive={diff.summary.totalHoursDelta <= 0}
            />
            <SummaryCard
              label="Cost"
              value={formatDelta(diff.summary.totalCostDelta, (v) => formatMoney(v))}
              positive={diff.summary.totalCostDelta <= 0}
            />
            <SummaryCard
              label="Price"
              value={formatDelta(diff.summary.totalPriceDelta, (v) => formatMoney(v))}
              positive={diff.summary.totalPriceDelta >= 0}
            />
            <SummaryCard
              label="Margin"
              value={`${diff.summary.marginPercentB.toFixed(1)}% (${diff.summary.marginPercentDelta >= 0 ? "+" : ""}${diff.summary.marginPercentDelta.toFixed(1)}pp)`}
              positive={diff.summary.marginPercentDelta >= 0}
            />
            <SummaryCard label="Lines +" value={`+${diff.summary.linesAdded}`} positive />
            <SummaryCard label="Lines -" value={`-${diff.summary.linesRemoved}`} positive={diff.summary.linesRemoved === 0} />
            <SummaryCard label="Lines ~" value={String(diff.summary.linesChanged)} positive={diff.summary.linesChanged === 0} />
            <SummaryCard label="Resources ~" value={String(diff.summary.resourceSnapshotsChanged)} positive={diff.summary.resourceSnapshotsChanged === 0} />
          </div>

          {/* Demand line diffs */}
          <div className="rounded-3xl border border-gray-200 bg-white p-5 shadow-sm">
            <h3 className="mb-3 text-base font-semibold text-gray-900">Demand lines</h3>
            {filteredDemandDiffs.length === 0 ? (
              <p className="py-4 text-center text-sm text-gray-400">
                {hideUnchanged ? "No changes in demand lines." : "No demand lines to compare."}
              </p>
            ) : (
              <div className="overflow-x-auto">
                <table className="w-full text-left text-sm">
                  <thead>
                    <tr className="border-b border-gray-200 text-xs uppercase tracking-wider text-gray-500">
                      <th className="py-2 pr-3 font-medium">Name</th>
                      <th className="px-3 py-2 font-medium">Status</th>
                      <th className="px-3 py-2 text-right font-medium">Hours (A)</th>
                      <th className="px-3 py-2 text-right font-medium">Hours (B)</th>
                      <th className="px-3 py-2 text-right font-medium">Hours delta</th>
                      <th className="px-3 py-2 text-right font-medium">Cost (A)</th>
                      <th className="px-3 py-2 text-right font-medium">Cost (B)</th>
                      <th className="px-3 py-2 text-right font-medium">Cost delta</th>
                      <th className="px-3 py-2 text-right font-medium">Price (A)</th>
                      <th className="px-3 py-2 text-right font-medium">Price (B)</th>
                      <th className="pl-3 py-2 text-right font-medium">Price delta</th>
                    </tr>
                  </thead>
                  <tbody>
                    {filteredDemandDiffs.map((d, i) => (
                      <tr key={i} className={clsx("border-b border-gray-100", STATUS_ROW_STYLES[d.status])}>
                        <td className="py-2 pr-3 font-medium text-gray-900">{d.name}</td>
                        <td className="px-3 py-2">
                          <span className={clsx("rounded-full px-2 py-0.5 text-xs font-medium", STATUS_BADGE_STYLES[d.status])}>
                            {d.status}
                          </span>
                        </td>
                        <td className="px-3 py-2 text-right tabular-nums text-gray-700">{d.a?.hours.toFixed(1) ?? "\u2014"}</td>
                        <td className="px-3 py-2 text-right tabular-nums text-gray-700">{d.b?.hours.toFixed(1) ?? "\u2014"}</td>
                        <td className={clsx("px-3 py-2 text-right tabular-nums", deltaColor(d.hoursDelta))}>
                          {d.hoursDelta != null ? formatHoursDelta(d.hoursDelta) : "\u2014"}
                        </td>
                        <td className="px-3 py-2 text-right tabular-nums text-gray-700">
                          {d.a ? formatMoney(d.a.costTotalCents) : "\u2014"}
                        </td>
                        <td className="px-3 py-2 text-right tabular-nums text-gray-700">
                          {d.b ? formatMoney(d.b.costTotalCents) : "\u2014"}
                        </td>
                        <td className={clsx("px-3 py-2 text-right tabular-nums", deltaColor(d.costDelta))}>
                          {d.costDelta != null ? formatDelta(d.costDelta, (v) => formatMoney(v)) : "\u2014"}
                        </td>
                        <td className="px-3 py-2 text-right tabular-nums text-gray-700">
                          {d.a ? formatMoney(d.a.priceTotalCents) : "\u2014"}
                        </td>
                        <td className="px-3 py-2 text-right tabular-nums text-gray-700">
                          {d.b ? formatMoney(d.b.priceTotalCents) : "\u2014"}
                        </td>
                        <td className={clsx("pl-3 py-2 text-right tabular-nums", deltaColor(d.priceDelta))}>
                          {d.priceDelta != null ? formatDelta(d.priceDelta, (v) => formatMoney(v)) : "\u2014"}
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            )}
          </div>

          {/* Assumption diffs */}
          {(filteredAssumptionDiffs.length > 0 || !hideUnchanged) && (
            <div className="rounded-3xl border border-gray-200 bg-white p-5 shadow-sm">
              <h3 className="mb-3 text-base font-semibold text-gray-900">Assumptions</h3>
              {filteredAssumptionDiffs.length === 0 ? (
                <p className="py-4 text-center text-sm text-gray-400">
                  {hideUnchanged ? "No changes in assumptions." : "No assumptions to compare."}
                </p>
              ) : (
                <div className="overflow-x-auto">
                  <table className="w-full text-left text-sm">
                    <thead>
                      <tr className="border-b border-gray-200 text-xs uppercase tracking-wider text-gray-500">
                        <th className="py-2 pr-3 font-medium">Assumption</th>
                        <th className="px-3 py-2 font-medium">Status</th>
                        <th className="px-3 py-2 font-medium">Value (A)</th>
                        <th className="pl-3 py-2 font-medium">Value (B)</th>
                      </tr>
                    </thead>
                    <tbody>
                      {filteredAssumptionDiffs.map((d) => (
                        <tr key={d.key} className={clsx("border-b border-gray-100", STATUS_ROW_STYLES[d.status])}>
                          <td className="py-2 pr-3 font-medium text-gray-900">{d.label}</td>
                          <td className="px-3 py-2">
                            <span className={clsx("rounded-full px-2 py-0.5 text-xs font-medium", STATUS_BADGE_STYLES[d.status])}>
                              {d.status}
                            </span>
                          </td>
                          <td className="px-3 py-2 text-gray-700">{formatAssumptionValue(d.aValue)}</td>
                          <td className="pl-3 py-2 text-gray-700">{formatAssumptionValue(d.bValue)}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              )}
            </div>
          )}

          {/* Chapter subtotals */}
          {diff.chapterSubtotals.length > 0 && (
            <div className="rounded-3xl border border-gray-200 bg-white p-5 shadow-sm">
              <h3 className="mb-3 text-base font-semibold text-gray-900">By chapter</h3>
              <div className="overflow-x-auto">
                <table className="w-full text-left text-sm">
                  <thead>
                    <tr className="border-b border-gray-200 text-xs uppercase tracking-wider text-gray-500">
                      <th className="py-2 pr-3 font-medium">Chapter</th>
                      <th className="px-3 py-2 text-right font-medium">Hours (A)</th>
                      <th className="px-3 py-2 text-right font-medium">Hours (B)</th>
                      <th className="px-3 py-2 text-right font-medium">Hours delta</th>
                      <th className="px-3 py-2 text-right font-medium">Cost (A)</th>
                      <th className="px-3 py-2 text-right font-medium">Cost (B)</th>
                      <th className="pl-3 py-2 text-right font-medium">Cost delta</th>
                    </tr>
                  </thead>
                  <tbody>
                    {diff.chapterSubtotals.map((ch) => (
                      <tr key={ch.chapter} className={clsx("border-b border-gray-100", ch.costDelta !== 0 ? "bg-amber-50" : "")}>
                        <td className="py-2 pr-3 font-medium text-gray-900">{ch.chapter}</td>
                        <td className="px-3 py-2 text-right tabular-nums text-gray-700">{ch.hoursA.toFixed(1)}</td>
                        <td className="px-3 py-2 text-right tabular-nums text-gray-700">{ch.hoursB.toFixed(1)}</td>
                        <td className={clsx("px-3 py-2 text-right tabular-nums", deltaColor(ch.hoursDelta))}>
                          {formatHoursDelta(ch.hoursDelta)}
                        </td>
                        <td className="px-3 py-2 text-right tabular-nums text-gray-700">{formatMoney(ch.costA)}</td>
                        <td className="px-3 py-2 text-right tabular-nums text-gray-700">{formatMoney(ch.costB)}</td>
                        <td className={clsx("pl-3 py-2 text-right tabular-nums", deltaColor(ch.costDelta))}>
                          {formatDelta(ch.costDelta, (v) => formatMoney(v))}
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            </div>
          )}

          {/* Scope item diffs */}
          {filteredScopeDiffs.length > 0 && (
            <div className="rounded-3xl border border-gray-200 bg-white p-5 shadow-sm">
              <h3 className="mb-3 text-base font-semibold text-gray-900">
                Scope items
                {(diff.summary.scopeItemsAdded > 0 || diff.summary.scopeItemsRemoved > 0 || diff.summary.scopeItemsChanged > 0) && (
                  <span className="ml-2 text-sm font-normal text-gray-500">
                    {diff.summary.scopeItemsAdded > 0 && <span className="text-emerald-600">+{diff.summary.scopeItemsAdded}</span>}
                    {diff.summary.scopeItemsRemoved > 0 && <span className="ml-2 text-red-600">-{diff.summary.scopeItemsRemoved}</span>}
                    {diff.summary.scopeItemsChanged > 0 && <span className="ml-2 text-amber-600">~{diff.summary.scopeItemsChanged}</span>}
                  </span>
                )}
              </h3>
              <div className="overflow-x-auto">
                <table className="w-full text-left text-sm">
                  <thead>
                    <tr className="border-b border-gray-200 text-xs uppercase tracking-wider text-gray-500">
                      <th className="py-2 pr-3 font-medium">Name</th>
                      <th className="px-3 py-2 font-medium">Type</th>
                      <th className="px-3 py-2 font-medium">Status</th>
                      <th className="px-3 py-2 text-right font-medium">Frames (A)</th>
                      <th className="px-3 py-2 text-right font-medium">Frames (B)</th>
                      <th className="px-3 py-2 text-right font-medium">Items (A)</th>
                      <th className="pl-3 py-2 text-right font-medium">Items (B)</th>
                    </tr>
                  </thead>
                  <tbody>
                    {filteredScopeDiffs.map((d, i) => (
                      <tr key={i} className={clsx("border-b border-gray-100", STATUS_ROW_STYLES[d.status])}>
                        <td className="py-2 pr-3 font-medium text-gray-900">{d.name}</td>
                        <td className="px-3 py-2 text-gray-600">{d.scopeType}</td>
                        <td className="px-3 py-2">
                          <span className={clsx("rounded-full px-2 py-0.5 text-xs font-medium", STATUS_BADGE_STYLES[d.status])}>
                            {d.status}
                          </span>
                        </td>
                        <td className="px-3 py-2 text-right tabular-nums text-gray-700">{d.a?.frameCount ?? "\u2014"}</td>
                        <td className="px-3 py-2 text-right tabular-nums text-gray-700">{d.b?.frameCount ?? "\u2014"}</td>
                        <td className="px-3 py-2 text-right tabular-nums text-gray-700">{d.a?.itemCount ?? "\u2014"}</td>
                        <td className="pl-3 py-2 text-right tabular-nums text-gray-700">{d.b?.itemCount ?? "\u2014"}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            </div>
          )}

          {/* Resource snapshot diffs */}
          {filteredResourceDiffs.length > 0 && (
            <div className="rounded-3xl border border-gray-200 bg-white p-5 shadow-sm">
              <h3 className="mb-3 text-base font-semibold text-gray-900">Resource rates</h3>
              <div className="overflow-x-auto">
                <table className="w-full text-left text-sm">
                  <thead>
                    <tr className="border-b border-gray-200 text-xs uppercase tracking-wider text-gray-500">
                      <th className="py-2 pr-3 font-medium">Name</th>
                      <th className="px-3 py-2 font-medium">Status</th>
                      <th className="px-3 py-2 text-right font-medium">LCR (A)</th>
                      <th className="px-3 py-2 text-right font-medium">LCR (B)</th>
                      <th className="px-3 py-2 text-right font-medium">UCR (A)</th>
                      <th className="px-3 py-2 text-right font-medium">UCR (B)</th>
                      <th className="px-3 py-2 font-medium">Location (A)</th>
                      <th className="pl-3 py-2 font-medium">Location (B)</th>
                    </tr>
                  </thead>
                  <tbody>
                    {filteredResourceDiffs.map((d, i) => (
                      <tr key={i} className={clsx("border-b border-gray-100", STATUS_ROW_STYLES[d.status])}>
                        <td className="py-2 pr-3 font-medium text-gray-900">{d.displayName}</td>
                        <td className="px-3 py-2">
                          <span className={clsx("rounded-full px-2 py-0.5 text-xs font-medium", STATUS_BADGE_STYLES[d.status])}>
                            {d.status}
                          </span>
                        </td>
                        <td className="px-3 py-2 text-right tabular-nums text-gray-700">{d.a ? formatMoney(d.a.lcrCents) : "\u2014"}</td>
                        <td className="px-3 py-2 text-right tabular-nums text-gray-700">{d.b ? formatMoney(d.b.lcrCents) : "\u2014"}</td>
                        <td className="px-3 py-2 text-right tabular-nums text-gray-700">{d.a ? formatMoney(d.a.ucrCents) : "\u2014"}</td>
                        <td className="px-3 py-2 text-right tabular-nums text-gray-700">{d.b ? formatMoney(d.b.ucrCents) : "\u2014"}</td>
                        <td className="px-3 py-2 text-gray-600">{d.a?.location ?? "\u2014"}</td>
                        <td className="pl-3 py-2 text-gray-600">{d.b?.location ?? "\u2014"}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            </div>
          )}
        </>
      )}
    </div>
  );
}

function SummaryCard({
  label,
  value,
  positive,
}: {
  label: string;
  value: string;
  positive: boolean;
}) {
  return (
    <div className="rounded-3xl border border-gray-200 bg-gray-50 p-4 text-center shadow-sm">
      <p className="text-xs font-medium uppercase tracking-wider text-gray-500">{label}</p>
      <p className={clsx("mt-1 text-lg font-semibold tabular-nums", positive ? "text-emerald-700" : "text-red-700")}>
        {value}
      </p>
    </div>
  );
}

function deltaColor(delta: number | undefined): string {
  if (delta == null || delta === 0) return "text-gray-400";
  return delta > 0 ? "text-red-600" : "text-emerald-600";
}

function formatAssumptionValue(value: unknown): string {
  if (value === undefined) return "\u2014";
  if (value === null) return "null";
  if (typeof value === "object") return JSON.stringify(value);
  return String(value);
}
