"use client";

import { useState } 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 { ProgressRing } from "~/components/ui/ProgressRing.js";

type GroupBy = "project" | "person" | "chapter";

type DemandRow = {
  id: string;
  name: string;
  shortCode: string;
  allocatedHours: number;
  requiredFTEs: number;
  resourceCount: number;
  derivation?: {
    periodStart: string;
    periodEnd: string;
    periodWorkingHoursBase: number;
    requiredHours: number | null;
    requiredFTEs: number;
    fillPct: number | null;
    demandSource: "DEMAND_REQUIREMENTS" | "PROJECT_STAFFING_REQS" | "NONE";
    calendarLocations: Array<{
      countryCode: string | null;
      federalState: string | null;
      metroCityName: string | null;
      resourceCount: number;
      allocatedHours: number;
    }>;
  };
};

type DemandDerivation = NonNullable<DemandRow["derivation"]>;
type DemandCalendarLocation = DemandDerivation["calendarLocations"][number];

function formatHours(value: number | null | undefined): string {
  if (value == null) return "—";
  return `${Number.isInteger(value) ? value.toFixed(0) : value.toFixed(1)}h`;
}

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

function formatDemandSource(source: DemandDerivation["demandSource"] | undefined): string {
  if (source === "DEMAND_REQUIREMENTS") return "Source: Demand requirements";
  if (source === "PROJECT_STAFFING_REQS") return "Source: Project staffing reqs";
  return "No demand basis";
}

function renderCalendarBasis(derivation: DemandDerivation): string {
  if (derivation.calendarLocations.length === 0) {
    return "No location-based booking basis";
  }

  return derivation.calendarLocations
    .slice(0, 2)
    .map((location) => `${formatLocation(location)} (${formatHours(location.allocatedHours)})`)
    .join(" · ");
}

export function DemandWidget({ config, onConfigChange }: WidgetProps) {
  const showDetails = config.showDetails === true;
  const groupBy = (config.groupBy as GroupBy) || "project";

  type SortKey = "name" | "allocatedHours" | "requiredFTEs" | "resourceCount";
  const [sortKey, setSortKey] = useState<SortKey>("allocatedHours");
  const [sortDir, setSortDir] = useState<"asc" | "desc">("desc");

  function toggleSort(key: SortKey) {
    if (sortKey === key) setSortDir((d) => (d === "asc" ? "desc" : "asc"));
    else { setSortKey(key); setSortDir(key === "name" ? "asc" : "desc"); }
  }

  const now = new Date();
  const startDate = new Date(now.getFullYear(), now.getMonth(), 1).toISOString();
  const endDate = new Date(now.getFullYear(), now.getMonth() + 3, 0).toISOString();

  const { data, isLoading, isFetching } = trpc.dashboard.getDemand.useQuery(
    { startDate, endDate, groupBy },
    { staleTime: 60_000, placeholderData: (prev) => prev },
  );

  if (isLoading && !data) {
    return (
      <div className="flex flex-col gap-3 pt-1">
        <div className="flex gap-1 border-b border-gray-200 pb-1">
          <div className="h-6 w-20 shimmer-skeleton rounded" />
          <div className="h-6 w-20 shimmer-skeleton rounded" />
          <div className="h-6 w-20 shimmer-skeleton rounded" />
        </div>
        {[...Array(6)].map((_, i) => (
          <div key={i} className="flex gap-3 px-3 py-1.5">
            <div className="h-3 flex-1 shimmer-skeleton rounded" />
            <div className="h-3 w-14 shimmer-skeleton rounded" />
            <div className="h-3 w-14 shimmer-skeleton rounded" />
          </div>
        ))}
      </div>
    );
  }

  const rows = (data ?? []) as DemandRow[];

  const sorted = [...rows].sort((a, b) => {
    const mult = sortDir === "asc" ? 1 : -1;
    switch (sortKey) {
      case "name": return mult * a.name.localeCompare(b.name);
      case "allocatedHours": return mult * (a.allocatedHours - b.allocatedHours);
      case "requiredFTEs": return mult * ((a.requiredFTEs as unknown as number ?? 0) - (b.requiredFTEs as unknown as number ?? 0));
      case "resourceCount": return mult * (a.resourceCount - b.resourceCount);
      default: return 0;
    }
  });

  function Ind({ k }: { k: SortKey }) {
    return sortKey === k
      ? <span className="text-[10px] ml-0.5">{sortDir === "asc" ? "▲" : "▼"}</span>
      : <span className="text-[10px] ml-0.5 text-gray-300">⇅</span>;
  }

  return (
    <div className="flex flex-col h-full gap-3">
      {/* Tab bar */}
      <div className="flex gap-1 border-b border-gray-200">
        {(["project", "person", "chapter"] as GroupBy[]).map((g) => (
          <button
            key={g}
            type="button"
            onClick={() => onConfigChange?.({ groupBy: g })}
            className={`px-3 py-1.5 text-xs font-medium capitalize transition-colors ${
              groupBy === g
                ? "border-b-2 border-brand-600 text-brand-700"
                : "text-gray-500 hover:text-gray-700"
            }`}
          >
            Per {g === "person" ? "Person" : g === "project" ? "Project" : "Chapter"}
          </button>
        ))}
      </div>

      {/* Table */}
      <div className={`overflow-auto flex-1 transition-opacity duration-150 ${isFetching ? "opacity-60" : "opacity-100"}`}>
        <table className="w-full text-xs">
          <thead className="bg-gray-50 sticky top-0">
            <tr>
              <th className="px-3 py-2 text-left font-medium text-gray-500">
                <span className="inline-flex items-center">
                  <button type="button" onClick={() => toggleSort("name")} className="inline-flex items-center hover:text-gray-700 cursor-pointer">
                    {groupBy === "project" ? "Project" : groupBy === "person" ? "Person" : "Chapter"}
                    <Ind k="name" />
                  </button>
                  {groupBy === "project" && <InfoTooltip content="Active projects with allocations in the current quarter. Short code shown before the name." />}
                  {groupBy === "person" && <InfoTooltip content="Resources with active allocations in the current quarter." />}
                  {groupBy === "chapter" && <InfoTooltip content="Organizational chapters (teams/departments) with active allocations in the current quarter." />}
                </span>
              </th>
              <th className="px-3 py-2 text-right font-medium text-gray-500">
                <span className="inline-flex items-center justify-end">
                  <button type="button" onClick={() => toggleSort("allocatedHours")} className="inline-flex items-center hover:text-gray-700 cursor-pointer">
                    Allocated h<Ind k="allocatedHours" />
                  </button>
                  <InfoTooltip
                    content="Total booked hours from active assignments in the current quarter."
                    position="bottom"
                  />
                </span>
              </th>
              {groupBy === "project" && (
                <th className="px-3 py-2 text-right font-medium text-gray-500">
                  <span className="inline-flex items-center justify-end">
                    <button type="button" onClick={() => toggleSort("requiredFTEs")} className="inline-flex items-center hover:text-gray-700 cursor-pointer">
                      Req. FTEs<Ind k="requiredFTEs" />
                    </button>
                    <InfoTooltip
                      content="Planned demand from demand requirements, with fallback to project staffing requirements for legacy projects. Red = booked hours fall short of the planned demand."
                      position="bottom"
                    />
                  </span>
                </th>
              )}
              <th className="px-3 py-2 text-right font-medium text-gray-500">
                <span className="inline-flex items-center justify-end">
                  <button type="button" onClick={() => toggleSort("resourceCount")} className="inline-flex items-center hover:text-gray-700 cursor-pointer">
                    {groupBy === "person" ? "Projects" : "Resources"}<Ind k="resourceCount" />
                  </button>
                  {groupBy === "person" ? (
                    <InfoTooltip content="Number of distinct projects this person is allocated to in the period." position="bottom" />
                  ) : (
                    <InfoTooltip content="Number of distinct resources allocated to this project/chapter in the period." position="bottom" />
                  )}
                </span>
              </th>
            </tr>
          </thead>
          <tbody className="divide-y divide-gray-100">
            {sorted.map((row) => (
              <tr key={row.id} className="hover:bg-gray-50">
                <td className="px-3 py-2 text-gray-900 max-w-[280px] align-top">
                  <div className="font-medium truncate">
                    {groupBy === "project" ? (
                      <span><span className="font-mono text-gray-500 mr-1">{row.shortCode}</span>{row.name}</span>
                    ) : (
                      row.name
                    )}
                  </div>
                  {showDetails && row.derivation ? (
                    <div className="mt-1 space-y-0.5 text-[10px] leading-4 text-gray-500">
                      <div>
                        {row.derivation.periodStart} to {row.derivation.periodEnd}
                      </div>
                      <div>{renderCalendarBasis(row.derivation)}</div>
                      {groupBy !== "project" ? (
                        <div>{formatHours(row.derivation.periodWorkingHoursBase)} per 1.0 FTE base</div>
                      ) : null}
                      {row.derivation.calendarLocations.length > 2 ? (
                        <div>+ {row.derivation.calendarLocations.length - 2} more calendar contexts</div>
                      ) : null}
                    </div>
                  ) : null}
                </td>
                <td className="px-3 py-2 text-right align-top">
                  <div className="text-gray-700">{row.allocatedHours}h</div>
                  {showDetails && row.derivation ? (
                    <div className="mt-1 space-y-0.5 text-[10px] leading-4 text-gray-500">
                      <div>{row.derivation.calendarLocations.length} calendar basis{row.derivation.calendarLocations.length === 1 ? "" : "es"}</div>
                      <div>{row.resourceCount} resource{row.resourceCount === 1 ? "" : "s"} in scope</div>
                    </div>
                  ) : null}
                </td>
                {groupBy === "project" && (
                  <td className="px-3 py-2 text-right align-top text-gray-700">
                    {(() => {
                      const ftes = row.requiredFTEs as unknown as number;
                      if (ftes <= 0) return "—";
                      const requiredHours = row.derivation?.requiredHours ?? null;
                      const rawFillPct = row.derivation?.fillPct ?? null;
                      const fillPct = Math.min(100, rawFillPct ?? 0);
                      const isBelowTarget = rawFillPct !== null ? rawFillPct < 100 : false;
                      const ringColor = isBelowTarget
                        ? "var(--color-red-500, #ef4444)"
                        : "var(--color-green-500, #22c55e)";
                      return (
                        <div className="inline-flex flex-col items-end gap-1">
                          <span className="inline-flex items-center gap-1.5">
                            <ProgressRing value={fillPct} size={22} strokeWidth={2.5} color={ringColor} />
                            <span className={isBelowTarget ? "text-red-600 font-semibold" : "text-green-700"}>
                              {ftes} FTE
                            </span>
                          </span>
                          {showDetails ? (
                            <div className="space-y-0.5 text-[10px] leading-4 text-gray-500">
                              <div>{formatHours(row.allocatedHours)} / {formatHours(requiredHours)}</div>
                              <div>{rawFillPct == null ? "—" : `${rawFillPct}% coverage`} · {formatHours(row.derivation?.periodWorkingHoursBase)} per 1.0 FTE</div>
                              <div>{formatDemandSource(row.derivation?.demandSource)}</div>
                            </div>
                          ) : null}
                        </div>
                      );
                    })()}
                  </td>
                )}
                <td className="px-3 py-2 text-right align-top text-gray-500">
                  <div>{row.resourceCount}</div>
                  {showDetails && row.derivation?.calendarLocations.length ? (
                    <div className="mt-1 text-[10px] leading-4 text-gray-500">
                      {row.derivation.calendarLocations.reduce((sum, location) => sum + location.resourceCount, 0)} resource entries across locations
                    </div>
                  ) : null}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
        {rows.length === 0 && (
          <div className="text-center py-8 text-sm text-gray-400">No demand data found.</div>
        )}
      </div>
    </div>
  );
}
