"use client";

import { useMemo, useState } from "react";
import Link from "next/link";
import { EstimateStatus, type EstimateVersionStatus } from "@nexus/shared";
import { clsx } from "clsx";
import { EstimateWizard } from "~/components/estimates/EstimateWizard.js";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
import { usePermissions } from "~/hooks/usePermissions.js";
import { formatDateLong, formatMoney } from "~/lib/format.js";
import { trpc } from "~/lib/trpc/client.js";

type EstimateMetric = {
  id: string;
  key: string;
  label: string;
  valueDecimal: number;
  valueCents: number | null;
  currency: string | null;
};

type EstimateScopeItem = {
  id: string;
  name: string;
  description: string | null;
  scopeType: string;
};

type EstimateDemandLine = {
  id: string;
  name: string;
  hours: number;
  costTotalCents: number;
  priceTotalCents: number;
  currency: string;
  chapter: string | null;
};

type EstimateVersion = {
  versionNumber: number;
  label: string | null;
  status: EstimateVersionStatus;
  notes: string | null;
  metrics: EstimateMetric[];
  scopeItems: EstimateScopeItem[];
  demandLines: EstimateDemandLine[];
};

type EstimateProjectRef = {
  shortCode: string;
  name: string;
};

type EstimateListItem = {
  id: string;
  name: string;
  status: EstimateStatus;
  opportunityId: string | null;
  updatedAt: Date | string;
  project: EstimateProjectRef | null;
  versions: Array<Pick<EstimateVersion, "versionNumber" | "status">>;
};

type EstimateDetail = {
  id: string;
  name: string;
  status: EstimateStatus;
  project: EstimateProjectRef | null;
  versions: EstimateVersion[];
};

const STATUS_STYLES: Record<EstimateStatus, string> = {
  DRAFT: "bg-slate-100 text-slate-700 dark:bg-slate-800 dark:text-slate-300",
  IN_REVIEW: "bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-300",
  APPROVED: "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-300",
  ARCHIVED: "bg-zinc-200 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-300",
};

const VERSION_STYLES: Record<EstimateVersionStatus, string> = {
  WORKING: "bg-sky-100 text-sky-700 dark:bg-sky-900/30 dark:text-sky-300",
  BASELINE: "bg-violet-100 text-violet-700 dark:bg-violet-900/30 dark:text-violet-300",
  SUBMITTED: "bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-300",
  APPROVED: "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-300",
  SUPERSEDED: "bg-zinc-200 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-300",
};

function formatMetricValue(metric: EstimateMetric) {
  if (metric.valueCents != null) {
    return formatMoney(metric.valueCents, metric.currency ?? "EUR");
  }
  if (metric.key === "margin_percent") {
    return `${metric.valueDecimal.toFixed(0)}%`;
  }
  return new Intl.NumberFormat("de-DE", { maximumFractionDigits: 1 }).format(metric.valueDecimal);
}

function getLatestVersion(estimate: EstimateDetail | null | undefined) {
  if (!estimate) return null;
  let latest = estimate.versions[0] ?? null;
  for (const version of estimate.versions) {
    if (!latest || version.versionNumber > latest.versionNumber) {
      latest = version;
    }
  }
  return latest;
}

function EstimateDetailPanel({
  estimate,
  onClone,
  cloning,
}: {
  estimate: EstimateDetail;
  onClone?: (id: string) => void;
  cloning?: boolean;
}) {
  const latestVersion = getLatestVersion(estimate);
  const latestMetrics = latestVersion?.metrics ?? [];

  return (
    <aside className="app-surface h-full p-5">
      <div className="flex items-start justify-between gap-4">
        <div>
          <p className="text-xs font-semibold uppercase tracking-[0.2em] text-gray-400">
            Estimate detail{" "}
            <InfoTooltip content="Pre-project cost and effort calculation. Estimates model staffing demand, scope, and financials before work begins." />
          </p>
          <h2 className="mt-2 text-xl font-semibold text-gray-900 dark:text-gray-50">
            {estimate.name}
          </h2>
          <p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
            {estimate.project
              ? `${estimate.project.shortCode} - ${estimate.project.name}`
              : "Standalone estimate"}
          </p>
        </div>
        <span
          className={clsx(
            "rounded-full px-3 py-1 text-xs font-semibold",
            STATUS_STYLES[estimate.status],
          )}
        >
          {estimate.status.replace("_", " ")}
        </span>
      </div>

      <div className="mt-4 flex gap-2">
        <Link
          href={`/estimates/${estimate.id}`}
          className="inline-flex items-center justify-center rounded-2xl border border-brand-200 dark:border-sky-700 bg-brand-50 dark:bg-sky-950/40 px-4 py-2 text-sm font-semibold text-brand-700 dark:text-sky-300 transition hover:border-brand-300 dark:hover:border-sky-600 hover:bg-brand-100 dark:hover:bg-sky-900/40"
        >
          Open workspace
        </Link>
        {onClone && (
          <button
            type="button"
            disabled={cloning}
            onClick={() => onClone(estimate.id)}
            className="inline-flex items-center justify-center rounded-2xl border border-gray-200 bg-white px-4 py-2 text-sm font-semibold text-gray-700 transition hover:border-gray-300 hover:bg-gray-50 disabled:opacity-50 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-200 dark:hover:bg-gray-800"
          >
            {cloning ? "Cloning..." : "Clone"}
          </button>
        )}
      </div>

      {latestVersion ? (
        <>
          <div className="mt-5 flex items-center gap-2">
            <span className="text-sm font-medium text-gray-700 dark:text-gray-300">
              Version {latestVersion.versionNumber}
              {latestVersion.label ? ` - ${latestVersion.label}` : ""}
            </span>
            <span
              className={clsx(
                "rounded-full px-2 py-0.5 text-xs font-medium",
                VERSION_STYLES[latestVersion.status],
              )}
            >
              {latestVersion.status}
            </span>
          </div>

          {latestMetrics.length > 0 && (
            <div className="mt-5 grid gap-3 sm:grid-cols-2">
              {latestMetrics.map((metric) => (
                <div
                  key={metric.id}
                  className="rounded-2xl border border-gray-100 bg-gray-50 px-4 py-3 dark:border-gray-800 dark:bg-gray-900/70"
                >
                  <p className="text-xs uppercase tracking-wide text-gray-400">{metric.label}</p>
                  <p className="mt-1 text-lg font-semibold text-gray-900 dark:text-gray-100">
                    {formatMetricValue(metric)}
                  </p>
                </div>
              ))}
            </div>
          )}

          {latestVersion.notes && (
            <div className="mt-5 rounded-2xl border border-gray-100 bg-gray-50 p-4 dark:border-gray-800 dark:bg-gray-900/70">
              <p className="text-xs uppercase tracking-wide text-gray-400">Version notes</p>
              <p className="mt-2 text-sm text-gray-700 dark:text-gray-200">{latestVersion.notes}</p>
            </div>
          )}

          <div className="mt-5 grid gap-5 xl:grid-cols-2">
            <section>
              <div className="flex items-center justify-between">
                <h3 className="text-sm font-semibold text-gray-900 dark:text-gray-100">
                  Scope items{" "}
                  <InfoTooltip content="Deliverables or work packages that define what is included in this estimate." />
                </h3>
                <span className="text-xs text-gray-400">{latestVersion.scopeItems.length}</span>
              </div>
              <div className="mt-3 space-y-2">
                {latestVersion.scopeItems.length === 0 ? (
                  <p className="rounded-2xl border border-dashed border-gray-200 dark:border-gray-700 px-4 py-3 text-sm text-gray-400">
                    No scope rows captured yet.
                  </p>
                ) : (
                  latestVersion.scopeItems.map((item) => (
                    <div
                      key={item.id}
                      className="rounded-2xl border border-gray-100 px-4 py-3 dark:border-gray-800"
                    >
                      <div className="flex items-center justify-between gap-3">
                        <p className="font-medium text-gray-900 dark:text-gray-100">{item.name}</p>
                        <span className="text-xs text-gray-400">{item.scopeType}</span>
                      </div>
                      {item.description && (
                        <p className="mt-1 text-sm text-gray-600 dark:text-gray-300">
                          {item.description}
                        </p>
                      )}
                    </div>
                  ))
                )}
              </div>
            </section>

            <section>
              <div className="flex items-center justify-between">
                <h3 className="text-sm font-semibold text-gray-900 dark:text-gray-100">
                  Demand lines{" "}
                  <InfoTooltip content="Staffing demand rows. Each line represents a role or resource with hours, cost rate, and sell rate." />
                </h3>
                <span className="text-xs text-gray-400">{latestVersion.demandLines.length}</span>
              </div>
              <div className="mt-3 space-y-2">
                {latestVersion.demandLines.length === 0 ? (
                  <p className="rounded-2xl border border-dashed border-gray-200 dark:border-gray-700 px-4 py-3 text-sm text-gray-400">
                    No staffing demand captured yet.
                  </p>
                ) : (
                  latestVersion.demandLines.map((line) => (
                    <div
                      key={line.id}
                      className="rounded-2xl border border-gray-100 px-4 py-3 dark:border-gray-800"
                    >
                      <div className="flex items-center justify-between gap-3">
                        <p className="font-medium text-gray-900 dark:text-gray-100">{line.name}</p>
                        <p className="text-sm font-medium text-gray-600 dark:text-gray-300">
                          {line.hours.toFixed(1)} h
                        </p>
                      </div>
                      <div className="mt-2 flex flex-wrap gap-2 text-xs text-gray-500 dark:text-gray-400">
                        <span>{formatMoney(line.costTotalCents, line.currency)} cost</span>
                        <span>{formatMoney(line.priceTotalCents, line.currency)} sell</span>
                        {line.chapter && <span>{line.chapter}</span>}
                      </div>
                    </div>
                  ))
                )}
              </div>
            </section>
          </div>
        </>
      ) : (
        <p className="mt-6 rounded-2xl border border-dashed border-gray-200 dark:border-gray-700 px-4 py-6 text-sm text-gray-400">
          No versions available for this estimate yet.
        </p>
      )}
    </aside>
  );
}

function EstimateCard({
  estimate,
  active,
  onSelect,
  canInspect,
}: {
  estimate: EstimateListItem;
  active: boolean;
  onSelect: () => void;
  canInspect: boolean;
}) {
  const latestVersion = estimate.versions[0];

  return (
    <button
      type="button"
      onClick={onSelect}
      disabled={!canInspect}
      className={clsx(
        "w-full rounded-3xl border p-5 text-left transition",
        active
          ? "border-brand-500 bg-brand-50 shadow-sm dark:border-sky-400 dark:bg-sky-950/30"
          : "border-gray-200 bg-white hover:border-gray-300 hover:shadow-sm dark:border-gray-700 dark:bg-gray-900 dark:hover:border-gray-600",
        !canInspect && "cursor-default",
      )}
    >
      <div className="flex items-start justify-between gap-4">
        <div>
          <div className="flex items-center gap-2">
            <span
              className={clsx(
                "rounded-full px-2.5 py-1 text-xs font-semibold",
                STATUS_STYLES[estimate.status],
              )}
            >
              {estimate.status.replace("_", " ")}
            </span>
            {estimate.project && (
              <span className="rounded-full bg-gray-100 dark:bg-gray-800 px-2.5 py-1 text-xs font-medium text-gray-600 dark:text-gray-400">
                {estimate.project.shortCode}
              </span>
            )}
          </div>
          <h3 className="mt-3 text-lg font-semibold text-gray-900 dark:text-gray-50">
            {estimate.name}
          </h3>
          <p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
            {estimate.project ? estimate.project.name : "No linked project"}
          </p>
        </div>
        {latestVersion && (
          <span
            className={clsx(
              "rounded-full px-2.5 py-1 text-xs font-medium",
              VERSION_STYLES[latestVersion.status],
            )}
          >
            v{latestVersion.versionNumber}
          </span>
        )}
      </div>

      <div className="mt-5 grid gap-3 sm:grid-cols-2">
        <div>
          <p className="text-xs uppercase tracking-wide text-gray-400">
            Opportunity{" "}
            <InfoTooltip content="External CRM or sales reference ID linking this estimate to a sales opportunity." />
          </p>
          <p className="mt-1 text-sm text-gray-700 dark:text-gray-200">
            {estimate.opportunityId ?? "Not set"}
          </p>
        </div>
        <div>
          <p className="text-xs uppercase tracking-wide text-gray-400">
            Updated{" "}
            <InfoTooltip content="When this estimate or any of its versions was last modified." />
          </p>
          <p className="mt-1 text-sm text-gray-700 dark:text-gray-200">
            {formatDateLong(estimate.updatedAt)}
          </p>
        </div>
      </div>

      {!canInspect && (
        <p className="mt-4 text-xs text-gray-400 dark:text-gray-500">
          Detailed financial breakdown is limited to manager and controller roles.
        </p>
      )}
    </button>
  );
}

export function EstimatesClient() {
  const [search, setSearch] = useState("");
  const [status, setStatus] = useState<EstimateStatus | "">("");
  const [wizardOpen, setWizardOpen] = useState(false);
  const [selectedEstimateId, setSelectedEstimateId] = useState<string | null>(null);
  const { canEdit, canViewCosts } = usePermissions();
  const utils = trpc.useUtils();

  const cloneMutation = trpc.estimate.clone.useMutation({
    onSuccess: (cloned) => {
      void utils.estimate.list.invalidate();
      setSelectedEstimateId(cloned.id);
    },
  });

  const listQuery = trpc.estimate.list.useQuery(
    {
      query: search || undefined,
      status: status || undefined,
    },
    { staleTime: 15_000 },
  );

  const detailQuery = trpc.estimate.getById.useQuery(
    { id: selectedEstimateId ?? "" },
    {
      enabled: canViewCosts && !!selectedEstimateId,
      staleTime: 15_000,
    },
  );

  const estimates = (listQuery.data ?? []) as unknown as EstimateListItem[];

  const selectedEstimate = useMemo(() => {
    if (!canViewCosts) return null;
    return (detailQuery.data ?? null) as unknown as EstimateDetail | null;
  }, [canViewCosts, detailQuery.data]);

  return (
    <>
      <div className="app-page space-y-6">
        <div className="app-surface-strong overflow-hidden bg-gradient-to-br from-white via-white to-brand-50 p-6 dark:from-gray-900 dark:via-gray-900 dark:to-gray-900">
          <div className="flex flex-col gap-5 lg:flex-row lg:items-end lg:justify-between">
            <div>
              <p className="text-xs font-semibold uppercase tracking-[0.24em] text-brand-600">
                Estimating
              </p>
              <h1 className="mt-2 font-display text-3xl font-semibold text-gray-900 dark:text-gray-50">
                Browser-native estimate workspace
              </h1>
              <p className="mt-2 max-w-3xl text-sm text-gray-600 dark:text-gray-300">
                Build structured estimates from live projects, resources, and role data instead of
                maintaining a disconnected spreadsheet.
              </p>
            </div>
            {canEdit && (
              <button
                type="button"
                onClick={() => setWizardOpen(true)}
                className="inline-flex items-center justify-center rounded-2xl bg-brand-600 px-5 py-3 text-sm font-semibold text-white transition hover:bg-brand-700"
              >
                New Estimate
              </button>
            )}
          </div>

          <div className="mt-6 grid gap-3 lg:grid-cols-[minmax(0,1fr),220px]">
            <input
              type="search"
              value={search}
              onChange={(event) => setSearch(event.target.value)}
              placeholder="Search by estimate or opportunity"
              className="app-input rounded-2xl px-4 py-3"
            />
            <select
              value={status}
              onChange={(event) => setStatus(event.target.value as EstimateStatus | "")}
              className="app-select w-full rounded-2xl px-4 py-3"
            >
              <option value="">All statuses</option>
              {Object.values(EstimateStatus).map((value) => (
                <option key={value} value={value}>
                  {value.replace("_", " ")}
                </option>
              ))}
            </select>
          </div>
        </div>

        {listQuery.isLoading ? (
          <div className="app-surface-strong border-dashed px-6 py-14 text-center text-sm text-gray-400">
            Loading estimates...
          </div>
        ) : estimates.length === 0 ? (
          <div className="app-surface-strong border-dashed px-6 py-14 text-center">
            <p className="text-base font-medium text-gray-700 dark:text-gray-100">
              No estimates yet
            </p>
            <p className="mt-2 text-sm text-gray-400 dark:text-gray-500">
              Start with the wizard to create a connected estimate from Nexus data.
            </p>
          </div>
        ) : (
          <div className="grid gap-6 xl:grid-cols-[minmax(0,1.05fr),minmax(320px,0.95fr)]">
            <div className="space-y-4">
              {estimates.map((estimate) => (
                <EstimateCard
                  key={estimate.id}
                  estimate={estimate}
                  active={estimate.id === selectedEstimateId}
                  canInspect={canViewCosts}
                  onSelect={() => {
                    if (!canViewCosts) return;
                    setSelectedEstimateId((current) =>
                      current === estimate.id ? current : estimate.id,
                    );
                  }}
                />
              ))}
            </div>

            <div>
              {canViewCosts ? (
                selectedEstimate ? (
                  <EstimateDetailPanel
                    estimate={selectedEstimate}
                    {...(canEdit
                      ? {
                          onClone: (id: string) => cloneMutation.mutate({ sourceEstimateId: id }),
                          cloning: cloneMutation.isPending,
                        }
                      : {})}
                  />
                ) : (
                  <div className="app-surface-strong border-dashed px-6 py-14 text-center text-sm text-gray-400">
                    Select an estimate to inspect the current version, demand lines, and summary
                    metrics.
                  </div>
                )
              ) : (
                <div className="app-surface-strong border-dashed px-6 py-14 text-center text-sm text-gray-400">
                  Your role can access the estimate list, but not the detailed financial breakdown.
                </div>
              )}
            </div>
          </div>
        )}
      </div>

      {wizardOpen && <EstimateWizard onClose={() => setWizardOpen(false)} />}
    </>
  );
}
