"use client";

import { useState } from "react";
import { AlertCircle } from "lucide-react";
import { Card, Title } from "@tremor/react";
import {
  BarChart as RechartsBarChart,
  Bar,
  XAxis,
  YAxis,
  CartesianGrid,
  Tooltip,
  LabelList,
  ResponsiveContainer,
  Legend as RechartsLegend,
} from "recharts";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
} from "@/app/shadcn_components/ui/select";
import type { ClassifiedDeal } from "./types";

interface CompletionTrendsChartProps {
  deals: ClassifiedDeal[];
  projectCode?: string;
  onOpenTable?: (
    stage: string,
    deals: ClassifiedDeal[],
    columns?: (keyof ClassifiedDeal)[],
    columnLabels?: Partial<Record<keyof ClassifiedDeal, string>>,
  ) => void;
}

const METRICS = [
  { key: "bookings", label: "Bookings", dateField: "confirmedSurveyDate" },
  {
    key: "assessments",
    label: "Completed Assessments",
    dateField: "surveyedDate",
  },
  {
    key: "coordination",
    label: "Completed Coordination",
    dateField: "ioeV1Date",
  },
  { key: "design", label: "Completed Designs", dateField: "designDate" },
  {
    key: "lodgement",
    label: "Completed Lodgements",
    dateField: "fullLodgementDate",
  },
];

// Brand colour palette
const C = {
  blue:      "#5d6be0",
  midblue:   "#3943b7",
  lightblue: "#8b96e9",
  paleblue:  "#b8bef4",
  brown:     "#c4a47c",
};

function ChartTooltip({
  payload,
  active,
  label,
}: {
  payload?: { name: string; value: number; color: string }[];
  active?: boolean;
  label?: string;
}) {
  if (!active || !payload?.length) return null;
  // Filter out the internal _total key
  const visible = payload.filter((p) => p.name !== "_total");
  if (!visible.length) return null;
  return (
    <div className="bg-white border border-gray-200 rounded-lg shadow-lg px-3 py-2 text-sm min-w-[140px]">
      <p className="font-semibold text-gray-700 mb-1.5 border-b border-gray-100 pb-1">{label}</p>
      {visible.map((item, i) => (
        <div key={i} className="flex items-center justify-between gap-3 py-0.5">
          <div className="flex items-center gap-1.5">
            <span
              className="w-2.5 h-2.5 rounded-sm shrink-0"
              style={{ backgroundColor: item.color }}
            />
            <span className="text-gray-600 text-xs">{item.name}</span>
          </div>
          <span className="font-semibold text-gray-800 text-xs">{item.value}</span>
        </div>
      ))}
    </div>
  );
}

// Client-facing design type labels
const DESIGN_TYPE_LABELS: Record<string, string> = {
  "Archetype (Complex)":  "Bespoke (Complex)",
  "Archetype (Simple)":   "Bespoke (Simple)",
  "Repetitive (Complex)": "Standard (Complex)",
  "Repetitive (Simple)":  "Standard (Simple)",
};
const DESIGN_TYPE_ORDER = [
  "Bespoke (Complex)",
  "Bespoke (Simple)",
  "Standard (Complex)",
  "Standard (Simple)",
];

function getMondayOfWeek(date: Date): string {
  const d = new Date(date);
  const day = d.getUTCDay();
  d.setUTCDate(d.getUTCDate() - (day === 0 ? 6 : day - 1));
  d.setUTCHours(0, 0, 0, 0);
  return d.toISOString().split("T")[0];
}

function formatMonday(isoDate: string): string {
  return new Date(isoDate).toLocaleDateString("en-GB", {
    day: "numeric",
    month: "short",
    year: "numeric",
  });
}

function fillWeekGaps(keys: string[]): string[] {
  if (keys.length === 0) return [];
  const sorted = [...keys].sort();
  const result: string[] = [];
  const current = new Date(sorted[0]);
  const end = new Date(sorted[sorted.length - 1]);
  while (current <= end) {
    result.push(current.toISOString().split("T")[0]);
    current.setUTCDate(current.getUTCDate() + 7);
  }
  return result;
}

function aggregateByWeek(
  deals: ClassifiedDeal[],
  dateField: string,
  filter?: (deal: ClassifiedDeal) => boolean,
) {
  const weekCounts: Record<string, number> = {};
  for (const deal of deals) {
    if (filter && !filter(deal)) continue;
    const date = deal[dateField as keyof ClassifiedDeal] as string | Date | null;
    if (!date) continue;
    const d = new Date(date);
    if (isNaN(d.getTime())) continue;
    const key = getMondayOfWeek(d);
    weekCounts[key] = (weekCounts[key] || 0) + 1;
  }
  const allKeys = fillWeekGaps(Object.keys(weekCounts));
  return allKeys.map((isoKey) => ({
    week: formatMonday(isoKey),
    value: weekCounts[isoKey] ?? 0,
  }));
}

function aggregateCoordinationByWeek(
  deals: ClassifiedDeal[],
): Array<{ week: string; "V1 (MTP)": number; "V2 (Re-model)": number; _total: number }> {
  const v1Counts: Record<string, number> = {};
  const v2Counts: Record<string, number> = {};

  for (const deal of deals) {
    const status = (deal.coordinationStatus ?? "").toUpperCase();
    if (status.includes("(V1) IOE/MTP COMPLETE") && deal.ioeV1Date) {
      const d = new Date(deal.ioeV1Date);
      if (!isNaN(d.getTime())) {
        const key = getMondayOfWeek(d);
        v1Counts[key] = (v1Counts[key] || 0) + 1;
      }
    }
    if (status.includes("(V2) IOE/MTP COMPLETE") && deal.ioeV2Date) {
      const d = new Date(deal.ioeV2Date);
      if (!isNaN(d.getTime())) {
        const key = getMondayOfWeek(d);
        v2Counts[key] = (v2Counts[key] || 0) + 1;
      }
    }
  }

  const allKeys = fillWeekGaps(
    Array.from(new Set([...Object.keys(v1Counts), ...Object.keys(v2Counts)])),
  );

  return allKeys.map((isoKey) => {
    const v1 = v1Counts[isoKey] ?? 0;
    const v2 = v2Counts[isoKey] ?? 0;
    return { week: formatMonday(isoKey), "V1 (MTP)": v1, "V2 (Re-model)": v2, _total: v1 + v2 };
  });
}

function aggregateAssessmentsByWeek(
  deals: ClassifiedDeal[],
): Array<{ week: string; "Retrofit Assessment": number; EPC: number; _total: number }> {
  const retrofitCounts: Record<string, number> = {};
  const epcCounts: Record<string, number> = {};

  for (const deal of deals) {
    const o = deal.outcome ?? "";
    const isRetrofit = o === "Surveyed" || o === "Surveyed - Pending Upload";
    const isEpc = o === "EPC Completed";
    if (!isRetrofit && !isEpc) continue;
    if (!deal.surveyedDate) continue;
    const d = new Date(deal.surveyedDate);
    if (isNaN(d.getTime())) continue;
    const key = getMondayOfWeek(d);
    if (isRetrofit) retrofitCounts[key] = (retrofitCounts[key] || 0) + 1;
    if (isEpc) epcCounts[key] = (epcCounts[key] || 0) + 1;
  }

  const allKeys = fillWeekGaps(
    Array.from(new Set([...Object.keys(retrofitCounts), ...Object.keys(epcCounts)])),
  );

  return allKeys.map((isoKey) => {
    const r = retrofitCounts[isoKey] ?? 0;
    const e = epcCounts[isoKey] ?? 0;
    return { week: formatMonday(isoKey), "Retrofit Assessment": r, EPC: e, _total: r + e };
  });
}

function aggregateLodgementsByWeek(
  deals: ClassifiedDeal[],
): Array<{ week: string; "Stage 1 Lodgement": number; "Lodged Measures": number; _total: number }> {
  const stageCounts: Record<string, number> = {};
  const measuresCounts: Record<string, number> = {};

  for (const deal of deals) {
    if (deal.fullLodgementDate) {
      const d = new Date(deal.fullLodgementDate);
      if (!isNaN(d.getTime())) {
        const key = getMondayOfWeek(d);
        stageCounts[key] = (stageCounts[key] || 0) + 1;
      }
    }
    if (deal.measuresLodgementDate) {
      const d = new Date(deal.measuresLodgementDate);
      if (!isNaN(d.getTime())) {
        const key = getMondayOfWeek(d);
        measuresCounts[key] = (measuresCounts[key] || 0) + 1;
      }
    }
  }

  const allKeys = fillWeekGaps(
    Array.from(new Set([...Object.keys(stageCounts), ...Object.keys(measuresCounts)])),
  );

  return allKeys.map((isoKey) => {
    const s = stageCounts[isoKey] ?? 0;
    const m = measuresCounts[isoKey] ?? 0;
    return { week: formatMonday(isoKey), "Stage 1 Lodgement": s, "Lodged Measures": m, _total: s + m };
  });
}

function aggregateDesignsByWeek(
  deals: ClassifiedDeal[],
): Array<Record<string, string | number>> {
  const counts: Record<string, Record<string, number>> = {};

  for (const deal of deals) {
    if (deal.designStatus?.toUpperCase() !== "UPLOADED") continue;
    if (!deal.designDate) continue;
    const d = new Date(deal.designDate);
    if (isNaN(d.getTime())) continue;
    const key = getMondayOfWeek(d);
    const rawType = deal.designType ?? "Unknown";
    const label = DESIGN_TYPE_LABELS[rawType] ?? rawType;
    if (!counts[key]) counts[key] = {};
    counts[key][label] = (counts[key][label] || 0) + 1;
  }

  const allKeys = fillWeekGaps(Object.keys(counts));
  return allKeys.map((isoKey) => {
    const entry: Record<string, string | number> = { week: formatMonday(isoKey) };
    let total = 0;
    for (const label of DESIGN_TYPE_ORDER) {
      const v = counts[isoKey]?.[label] ?? 0;
      entry[label] = v;
      total += v;
    }
    entry._total = total;
    return entry;
  });
}

// Compute total completed count for metrics that support it
function computeTotalCompleted(
  metric: string,
  chartData: Record<string, string | number>[],
  categories: string[],
): number | null {
  if (!["bookings", "assessments", "coordination", "design"].includes(metric)) return null;
  return chartData.reduce((sum, row) => {
    return sum + categories.reduce((s, cat) => s + ((row[cat] as number) || 0), 0);
  }, 0);
}

export default function CompletionTrendsChart({
  deals,
  onOpenTable,
}: CompletionTrendsChartProps) {
  const [metric, setMetric] = useState(METRICS[0].key);

  const selectedMetric = METRICS.find((m) => m.key === metric)!;
  const isCoordination = metric === "coordination";
  const isAssessments  = metric === "assessments";
  const isLodgement    = metric === "lodgement";
  const isDesign       = metric === "design";
  const isStacked = isCoordination || isAssessments || isLodgement || isDesign;

  // Assessments (retrofit or EPC) with no date
  const undatedAssessments = isAssessments
    ? deals.filter((d) => {
        const o = d.outcome ?? "";
        return (
          (o === "Surveyed" || o === "Surveyed - Pending Upload" || o === "EPC Completed") &&
          !d.surveyedDate
        );
      })
    : [];

  // Dated assessments broken down by type — used for summary badges
  const retrofitDeals = isAssessments
    ? deals.filter((d) => {
        const o = d.outcome ?? "";
        return (o === "Surveyed" || o === "Surveyed - Pending Upload") && !!d.surveyedDate;
      })
    : [];
  const epcDeals = isAssessments
    ? deals.filter((d) => d.outcome === "EPC Completed" && !!d.surveyedDate)
    : [];

  // Build chart data
  let chartData: Record<string, string | number>[];
  let categories: string[];
  let colors: string[];

  if (isCoordination) {
    chartData = aggregateCoordinationByWeek(deals);
    categories = ["V1 (MTP)", "V2 (Re-model)"];
    colors = [C.blue, C.midblue];
  } else if (isAssessments) {
    chartData = aggregateAssessmentsByWeek(deals);
    categories = ["Retrofit Assessment", "EPC"];
    colors = [C.blue, C.midblue];
  } else if (isLodgement) {
    chartData = aggregateLodgementsByWeek(deals);
    categories = ["Stage 1 Lodgement", "Lodged Measures"];
    colors = [C.blue, C.lightblue];
  } else if (isDesign) {
    chartData = aggregateDesignsByWeek(deals);
    categories = DESIGN_TYPE_ORDER;
    colors = [C.midblue, C.blue, C.lightblue, C.paleblue];
  } else {
    const singleData = aggregateByWeek(deals, selectedMetric.dateField);
    chartData = singleData.map((d) => ({
      week: d.week,
      [selectedMetric.label]: d.value,
    }));
    categories = [selectedMetric.label];
    colors = [C.blue];
  }

  const totalCompleted = computeTotalCompleted(metric, chartData, categories);

  return (
    <Card className="p-6 border border-brandblue/10 bg-white shadow-sm">
      {/* Header row */}
      <div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4 mb-4">
        <div className="flex flex-col gap-2">
          <Title className="text-brandblue text-lg font-bold">
            Trends Over Time
          </Title>
          {isAssessments ? (
            <div className="flex flex-wrap gap-2">
              {([
                { label: "Retrofit Assessments", dealList: retrofitDeals },
                { label: "EPCs", dealList: epcDeals },
              ] as const).filter(({ dealList }) => dealList.length > 0).map(({ label, dealList }) => (
                <button
                  key={label}
                  type="button"
                  onClick={() =>
                    onOpenTable?.(
                      `Completed — ${label}`,
                      dealList,
                      ["dealname", "landlordPropertyId", "outcome", "surveyedDate"],
                      {
                        dealname: "Address",
                        landlordPropertyId: "Property Ref.",
                        outcome: "Work Type",
                        surveyedDate: "Survey Date",
                      },
                    )
                  }
                  className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-gradient-to-r from-brandmidblue/10 to-brandlightblue/50 border border-brandblue/20 shadow-sm hover:border-brandblue/40 hover:shadow-md transition-all cursor-pointer"
                >
                  <span className="text-brandmidblue font-bold text-base leading-none">{dealList.length}</span>
                  <span className="text-xs text-brandblue font-medium">{label}</span>
                  <span className="text-brandmidblue text-xs leading-none">✦</span>
                </button>
              ))}
            </div>
          ) : totalCompleted !== null && (
            <div className="inline-flex items-center gap-2 self-start px-3 py-1.5 rounded-full bg-gradient-to-r from-brandmidblue/10 to-brandlightblue/50 border border-brandblue/20 shadow-sm">
              <span className="text-brandmidblue font-bold text-base leading-none" suppressHydrationWarning>{totalCompleted}</span>
              <span className="text-xs text-brandblue font-medium">
                {metric === "bookings" ? "booked to date" : "completed to date"}
              </span>
              <span className="text-brandmidblue text-xs leading-none">✦</span>
            </div>
          )}
        </div>
        <div className="flex gap-2 items-start">
          <Select value={metric} onValueChange={setMetric}>
            <SelectTrigger className="w-56 h-9 text-sm border-gray-200">
              {METRICS.find((m) => m.key === metric)?.label}
            </SelectTrigger>
            <SelectContent>
              {METRICS.map((m) => (
                <SelectItem key={m.key} value={m.key} className="text-sm">
                  {m.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
      </div>

      {/* Undated external assessments — shown above the chart */}
      {isAssessments && undatedAssessments.length > 0 && (
        <div className="mb-4 flex items-center justify-between gap-3 p-3 rounded-lg border border-amber-200 bg-amber-50/60">
          <div className="flex items-center gap-2 min-w-0">
            <AlertCircle className="h-4 w-4 text-amber-500 shrink-0" />
            <span className="text-sm text-amber-700">
              <span className="font-semibold">{undatedAssessments.length}</span>{" "}
              external assessment{undatedAssessments.length !== 1 ? "s" : ""} have no date recorded
            </span>
          </div>
          {onOpenTable && (
            <button
              onClick={() =>
                onOpenTable(
                  "Undated External Assessments",
                  undatedAssessments,
                  ["dealname", "landlordPropertyId", "coordinator"],
                  {
                    dealname: "Address",
                    landlordPropertyId: "Property Ref.",
                    coordinator: "Surveyor",
                  },
                )
              }
              className="shrink-0 text-xs font-semibold text-amber-700 underline underline-offset-2 hover:text-amber-900 transition-colors"
            >
              View properties
            </button>
          )}
        </div>
      )}

      {/* Chart */}
      <ResponsiveContainer width="100%" height={288}>
        <RechartsBarChart data={chartData} margin={{ top: 20, right: 16, left: 0, bottom: 0 }}>
          <CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" vertical={false} />
          <XAxis
            dataKey="week"
            tick={{ fontSize: 10, fill: "#9ca3af" }}
            axisLine={false}
            tickLine={false}
          />
          <YAxis
            width={36}
            tick={{ fontSize: 10, fill: "#9ca3af" }}
            axisLine={false}
            tickLine={false}
            allowDecimals={false}
          />
          <Tooltip content={<ChartTooltip />} cursor={{ fill: "rgba(89,107,224,0.06)" }} />
          {categories.map((cat, i) => (
            <Bar
              key={cat}
              dataKey={cat}
              stackId={isStacked ? "stack" : undefined}
              fill={colors[i]}
              radius={i === categories.length - 1 || !isStacked ? [3, 3, 0, 0] : [0, 0, 0, 0]}
            >
              {/* For stacked bars: show total on the top (last) bar only via _total.
                  For non-stacked: show each bar's own value. */}
              {i === categories.length - 1 && (
                <LabelList
                  dataKey={isStacked ? "_total" : cat}
                  position="top"
                  style={{ fontSize: 10, fill: "#6b7280", fontWeight: 500 }}
                  formatter={(v: unknown) => (v === 0 ? "" : String(v))}
                />
              )}
            </Bar>
          ))}
        </RechartsBarChart>
      </ResponsiveContainer>

      {/* Legend for stacked charts */}
      {isStacked && (
        <RechartsLegend
          wrapperStyle={{ paddingTop: "12px", fontSize: "12px", color: "#6b7280" }}
          content={() => (
            <ul style={{ display: "flex", flexWrap: "wrap", gap: "8px", padding: 0, margin: 0, listStyle: "none" }}>
              {categories.map((cat, i) => (
                <li key={cat} style={{ display: "flex", alignItems: "center", gap: "4px" }}>
                  <span style={{ display: "inline-block", width: 10, height: 10, backgroundColor: colors[i], flexShrink: 0 }} />
                  <span>{cat}</span>
                </li>
              ))}
            </ul>
          )}
        />
      )}
    </Card>
  );
}
