"use client";

import { useMemo } from "react";
import { trpc } from "~/lib/trpc/client.js";
import type { WidgetProps } from "~/components/dashboard/widget-registry.js";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
import { WidgetFilterBar, type WidgetFilter } from "~/components/dashboard/WidgetFilterBar.js";
import { useWidgetFilterOptions } from "~/hooks/useWidgetFilterOptions.js";

function colorClass(pct: number): string {
  if (pct > 90) return "bg-red-500";
  if (pct > 70) return "bg-amber-400";
  return "bg-green-500";
}

function textColorClass(pct: number): string {
  if (pct > 90) return "text-red-700";
  if (pct > 70) return "text-amber-700";
  return "text-green-700";
}

type BudgetForecastLocation = {
  countryCode?: string | null;
  countryName?: string | null;
  federalState?: string | null;
  metroCityName?: string | null;
  activeAssignmentCount?: number;
  burnRateCents?: number;
};

type BudgetForecastRow = {
  projectId?: string;
  projectName: string;
  shortCode: string;
  clientId: string | null;
  clientName: string | null;
  budgetCents: number;
  spentCents: number;
  remainingCents?: number;
  burnRate: number;
  estimatedExhaustionDate: string | null;
  pctUsed: number;
  activeAssignmentCount?: number;
  calendarLocations?: BudgetForecastLocation[];
  derivation?: {
    periodStart: string;
    periodEnd: string;
    calendarContextCount: number;
    holidayAwareAssignmentCount: number;
    fallbackAssignmentCount: number;
    baseBurnRateCents: number;
    adjustedBurnRateCents: number;
    publicHolidayDayEquivalent: number;
    publicHolidayCostDeductionCents: number;
    absenceDayEquivalent: number;
    absenceCostDeductionCents: number;
  } | null;
};

function formatCurrency(cents: number | undefined): string {
  if (cents === undefined) return "—";
  return `${(cents / 100).toLocaleString("de-DE", { maximumFractionDigits: 0 })} €`;
}

function formatDayEquivalent(value: number | undefined): string {
  if (value === undefined) return "—";
  return Number.isInteger(value) ? String(value) : value.toFixed(1);
}

function formatLocation(location: BudgetForecastLocation): string {
  const parts = [
    location.countryCode ?? location.countryName ?? null,
    location.federalState ?? null,
    location.metroCityName ?? null,
  ].filter((part): part is string => Boolean(part));
  return parts.length > 0 ? parts.join(" / ") : "No calendar context";
}

function SummaryCard({
  label,
  value,
  helper,
}: {
  label: string;
  value: string;
  helper?: string;
}) {
  return (
    <div className="rounded-2xl border border-gray-200 bg-gray-50/80 px-3 py-2 dark:border-gray-800 dark:bg-gray-950/40">
      <div className="text-[10px] font-semibold uppercase tracking-[0.16em] text-gray-500 dark:text-gray-400">
        {label}
      </div>
      <div className="mt-1 text-sm font-semibold text-gray-900 dark:text-gray-100">{value}</div>
      {helper ? (
        <div className="mt-0.5 text-[10px] leading-4 text-gray-500 dark:text-gray-400">{helper}</div>
      ) : null}
    </div>
  );
}

export function BudgetForecastWidget({ config, onConfigChange }: WidgetProps) {
  const showDetails = config.showDetails === true;
  const { clients } = useWidgetFilterOptions({ clients: true });

  const filters = useMemo<WidgetFilter[]>(
    () => [
      { type: "search", key: "search", placeholder: "Search project..." },
      { type: "select", key: "clientId", label: "Client", options: clients },
    ],
    [clients],
  );

  const { data, isLoading } = trpc.dashboard.getBudgetForecast.useQuery(
    undefined,
    { staleTime: 60_000, placeholderData: (prev) => prev },
  );

  const search = ((config.search as string) ?? "").toLowerCase();
  const clientId = (config.clientId as string) ?? "";

  const rows = useMemo(() => {
    const all = (data ?? []) as BudgetForecastRow[];
    return all.filter((r) => {
      if (search && !r.projectName.toLowerCase().includes(search) && !r.shortCode.toLowerCase().includes(search)) return false;
      if (clientId && r.clientId !== clientId) return false;
      return true;
    });
  }, [data, search, clientId]);

  const totals = useMemo(() => rows.reduce((acc, row) => {
    acc.budgetCents += row.budgetCents;
    acc.spentCents += row.spentCents;
    acc.remainingCents += row.remainingCents ?? Math.max(0, row.budgetCents - row.spentCents);
    acc.burnRate += row.burnRate;
    acc.activeAssignmentCount += row.activeAssignmentCount ?? 0;
    acc.baseBurnRateCents += row.derivation?.baseBurnRateCents ?? row.burnRate;
    acc.publicHolidayCostDeductionCents += row.derivation?.publicHolidayCostDeductionCents ?? 0;
    acc.absenceCostDeductionCents += row.derivation?.absenceCostDeductionCents ?? 0;
    return acc;
  }, {
    budgetCents: 0,
    spentCents: 0,
    remainingCents: 0,
    burnRate: 0,
    activeAssignmentCount: 0,
    baseBurnRateCents: 0,
    publicHolidayCostDeductionCents: 0,
    absenceCostDeductionCents: 0,
  }), [rows]);

  if (isLoading && !data) {
    return (
      <div className="flex flex-col gap-1 pt-1">
        {[...Array(5)].map((_, i) => (
          <div key={i} className="flex items-center gap-3 px-3 py-2">
            <div className="h-3 w-16 shimmer-skeleton rounded" />
            <div className="h-3 flex-1 shimmer-skeleton rounded" />
            <div className="h-3 w-12 shimmer-skeleton rounded" />
          </div>
        ))}
      </div>
    );
  }

  if (rows.length === 0) {
    return (
      <div className="flex flex-col h-full">
        <WidgetFilterBar filters={filters} values={config} onChange={onConfigChange ?? (() => {})} />
        <div className="flex items-center justify-center flex-1 text-sm text-gray-400">
          No active projects with budgets.
        </div>
      </div>
    );
  }

  return (
    <div className="flex flex-col h-full overflow-hidden">
      <WidgetFilterBar filters={filters} values={config} onChange={onConfigChange ?? (() => {})} />
      <div className="mb-3 grid gap-2 sm:grid-cols-2 xl:grid-cols-4">
        <SummaryCard
          label="Projects"
          value={String(rows.length)}
          {...(showDetails ? { helper: `${totals.activeAssignmentCount} active assignments in scope` } : {})}
        />
        <SummaryCard
          label="Budget"
          value={formatCurrency(totals.budgetCents)}
          {...(showDetails ? { helper: `${formatCurrency(totals.spentCents)} spent` } : {})}
        />
        <SummaryCard
          label="Remaining"
          value={formatCurrency(totals.remainingCents)}
          {...(showDetails
            ? { helper: `${rows.filter((row) => row.remainingCents !== undefined && row.remainingCents <= 0).length} exhausted` }
            : {})}
        />
        <SummaryCard
          label="Burn / Month"
          value={formatCurrency(totals.burnRate)}
          {...(showDetails ? {
            helper: `Base ${formatCurrency(totals.baseBurnRateCents)} · Hol -${formatCurrency(totals.publicHolidayCostDeductionCents)} · Abs -${formatCurrency(totals.absenceCostDeductionCents)}`,
          } : {})}
        />
      </div>
      <div className="overflow-auto flex-1">
        <table className="w-full text-xs">
          <thead className="bg-gray-50 dark:bg-gray-800/50 sticky top-0">
            <tr>
              <th className="px-3 py-2 text-left font-medium text-gray-500 dark:text-gray-400">
                Project <InfoTooltip content="Active projects with a defined budget" />
              </th>
              <th className="px-3 py-2 text-left font-medium text-gray-500 dark:text-gray-400">
                Budget Usage <InfoTooltip content="Percentage of total budget consumed by current allocations" />
              </th>
              <th className="px-3 py-2 text-right font-medium text-gray-500 dark:text-gray-400">
                Burn/mo <InfoTooltip content="Current-month burn rate based on active allocations, adjusted for regional holidays and approved absences where resource calendars are available." />
              </th>
              <th className="px-3 py-2 text-right font-medium text-gray-500 dark:text-gray-400">
                Exhaustion <InfoTooltip content="Projected date when budget will be fully consumed at the current burn rate" />
              </th>
            </tr>
          </thead>
          <tbody className="divide-y divide-gray-100 dark:divide-gray-800">
            {rows.map((row) => (
              <tr key={row.shortCode} className="hover:bg-gray-50 dark:hover:bg-gray-800/30">
                <td className="px-3 py-2 font-medium text-gray-900 dark:text-gray-100 max-w-[260px] align-top">
                  <div>
                    <span className="font-mono text-gray-500 dark:text-gray-400 mr-1">{row.shortCode}</span>
                    {row.projectName}
                  </div>
                  <div className="mt-1 text-[10px] font-normal leading-4 text-gray-500 dark:text-gray-400">
                    {row.clientName ?? "No client"}
                  </div>
                  {showDetails ? (
                    <div className="mt-1 space-y-1 text-[10px] font-normal leading-4 text-gray-500 dark:text-gray-400">
                      <div className="grid gap-x-3 gap-y-0.5 sm:grid-cols-2">
                        <div>{row.activeAssignmentCount ?? 0} active assignments</div>
                        <div>Remaining {formatCurrency(row.remainingCents ?? Math.max(0, row.budgetCents - row.spentCents))}</div>
                        {row.derivation ? (
                          <>
                            <div>{row.derivation.calendarContextCount} calendar bases</div>
                            <div>
                              {row.derivation.holidayAwareAssignmentCount} holiday-aware
                              {row.derivation.fallbackAssignmentCount > 0 ? ` · ${row.derivation.fallbackAssignmentCount} fallback` : ""}
                            </div>
                          </>
                        ) : null}
                      </div>
                      <div className="flex flex-wrap gap-1">
                        {row.calendarLocations && row.calendarLocations.length > 0 ? (
                          row.calendarLocations.slice(0, 4).map((location) => (
                            <span
                              key={`${location.countryCode ?? location.countryName ?? "na"}:${location.federalState ?? "na"}:${location.metroCityName ?? "na"}`}
                              className="inline-flex items-center rounded-full border border-gray-200 bg-gray-50 px-2 py-0.5 dark:border-gray-700 dark:bg-gray-900/70"
                            >
                              {formatLocation(location)} · {location.activeAssignmentCount ?? 0}x · {formatCurrency(location.burnRateCents)}
                            </span>
                          ))
                        ) : (
                          <span>No active calendar basis in the current month</span>
                        )}
                      </div>
                    </div>
                  ) : null}
                </td>
                <td className="px-3 py-2 align-top">
                  <div className="flex items-center gap-2">
                    <div className="flex-1 h-2 bg-gray-100 dark:bg-gray-700 rounded-full overflow-hidden">
                      <div
                        className={`h-full rounded-full transition-all ${colorClass(row.pctUsed)}`}
                        style={{ width: `${Math.min(row.pctUsed, 100)}%` }}
                      />
                    </div>
                    <span className={`text-[11px] font-semibold tabular-nums w-10 text-right ${textColorClass(row.pctUsed)}`}>
                      {row.pctUsed}%
                    </span>
                  </div>
                  <div className="mt-1 text-[10px] leading-4 text-gray-500 dark:text-gray-400">
                    {formatCurrency(row.spentCents)} / {formatCurrency(row.budgetCents)}
                  </div>
                  {showDetails ? (
                    <div className="text-[10px] leading-4 text-gray-500 dark:text-gray-400">
                      Remaining {formatCurrency(row.remainingCents ?? Math.max(0, row.budgetCents - row.spentCents))}
                    </div>
                  ) : null}
                </td>
                <td className="px-3 py-2 text-right text-gray-700 dark:text-gray-300 tabular-nums align-top">
                  <div>
                    {row.burnRate > 0 ? formatCurrency(row.burnRate) : "\u2014"}
                  </div>
                  {showDetails ? (
                    <div className="mt-1 space-y-0.5 text-[10px] leading-4 text-gray-500 dark:text-gray-400">
                      {row.derivation ? (
                        <>
                          <div>
                            Base {formatCurrency(row.derivation.baseBurnRateCents)} {"->"} Adj {formatCurrency(row.derivation.adjustedBurnRateCents)}
                          </div>
                          <div>
                            Hol -{formatCurrency(row.derivation.publicHolidayCostDeductionCents)} ({formatDayEquivalent(row.derivation.publicHolidayDayEquivalent)}d) · Abs -{formatCurrency(row.derivation.absenceCostDeductionCents)} ({formatDayEquivalent(row.derivation.absenceDayEquivalent)}d)
                          </div>
                          <div>
                            {row.derivation.holidayAwareAssignmentCount} holiday-aware assignment{row.derivation.holidayAwareAssignmentCount === 1 ? "" : "s"}
                            {row.derivation.fallbackAssignmentCount > 0 ? ` · ${row.derivation.fallbackAssignmentCount} fallback` : ""}
                          </div>
                        </>
                      ) : (
                        <div>{row.activeAssignmentCount ?? 0} active assignments</div>
                      )}
                      {(row.calendarLocations ?? []).slice(0, 3).map((location) => (
                        <div key={`${location.countryCode ?? location.countryName ?? "na"}:${location.federalState ?? "na"}:${location.metroCityName ?? "na"}`}>
                          {formatLocation(location)} · {location.activeAssignmentCount ?? 0}x · {formatCurrency(location.burnRateCents)}
                        </div>
                      ))}
                    </div>
                  ) : null}
                </td>
                <td className="px-3 py-2 text-right text-gray-500 dark:text-gray-400 tabular-nums align-top">
                  <div>{row.estimatedExhaustionDate ?? "\u2014"}</div>
                  {showDetails ? (
                    <div className="mt-1 text-[10px] leading-4 text-gray-500 dark:text-gray-400">
                      at {formatCurrency(row.burnRate)} / month
                    </div>
                  ) : null}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}
