"use client";

import React, { useMemo, useState } from "react";
import { useMutation, useQuery } from "@tanstack/react-query";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/app/shadcn_components/ui/table";
import { Input } from "@/app/shadcn_components/ui/input";
import { Button } from "@/app/shadcn_components/ui/button";
import { Badge } from "@/app/shadcn_components/ui/badge";
import { Checkbox } from "@/app/shadcn_components/ui/checkbox";
import { Search, Save, ChevronDown, ChevronRight } from "lucide-react";
import { STAGE_COLORS } from "./types";
import type { ClassifiedDeal, PortfolioCapabilityType, ApprovalsByDeal } from "./types";
import { ApprovalConfirmDialog, type PendingDiff } from "./ApprovalConfirmDialog";

type AuditEvent = {
  id: string;
  hubspotDealId: string;
  measureName: string;
  action: string; // 'approved' | 'unapproved'
  actedByEmail: string;
  actedByName: string | null;
  actedAt: string; // ISO string
};

type Props = {
  data: ClassifiedDeal[];
  userCapability: PortfolioCapabilityType;
  approvalsByDeal: ApprovalsByDeal;
  portfolioId: string;
};

function parseMeasures(raw: string | null | undefined): string[] {
  if (!raw) return [];
  return raw.split(",").map((m) => m.trim()).filter(Boolean);
}

function ApprovalStatus({
  proposed,
  approved,
}: {
  proposed: string[];
  approved: string[];
}) {
  if (proposed.length === 0) return null;
  const approvedSet = new Set(approved);
  const approvedCount = proposed.filter((m) => approvedSet.has(m)).length;

  if (approvedCount === 0) {
    return (
      <Badge className="bg-amber-50 text-amber-700 border border-amber-200 text-xs">
        Pending
      </Badge>
    );
  }
  if (approvedCount === proposed.length) {
    return (
      <Badge className="bg-emerald-50 text-emerald-700 border border-emerald-200 text-xs">
        Fully Approved
      </Badge>
    );
  }
  return (
    <Badge className="bg-blue-50 text-blue-700 border border-blue-200 text-xs">
      {approvedCount}/{proposed.length} Approved
    </Badge>
  );
}

function formatDate(iso: string) {
  return new Date(iso).toLocaleString("en-GB", {
    day: "numeric",
    month: "short",
    year: "numeric",
    hour: "2-digit",
    minute: "2-digit",
  });
}

function ActivityLog({
  dealId,
  portfolioId,
}: {
  dealId: string;
  portfolioId: string;
}) {
  const { data, isLoading } = useQuery<{ events: AuditEvent[] }>({
    queryKey: ["approvalEvents", portfolioId, dealId],
    queryFn: async () => {
      const res = await fetch(
        `/api/portfolio/${portfolioId}/approvals?dealIds=${dealId}&include=events`,
      );
      if (!res.ok) throw new Error("Failed to fetch events");
      return res.json();
    },
    staleTime: 30_000,
  });

  if (isLoading) {
    return (
      <p className="text-xs text-gray-400 py-2 pl-4">Loading activity…</p>
    );
  }

  const events = data?.events ?? [];

  if (events.length === 0) {
    return (
      <p className="text-xs text-gray-400 py-2 pl-4">No activity yet.</p>
    );
  }

  return (
    <div className="pl-4 pr-2 pb-3 space-y-1.5">
      {events.map((e) => (
        <div key={e.id} className="flex items-center gap-2 text-xs">
          <span
            className={`px-1.5 py-0.5 rounded text-xs font-medium ${
              e.action === "approved"
                ? "bg-emerald-50 text-emerald-700"
                : "bg-red-50 text-red-600"
            }`}
          >
            {e.action === "approved" ? "Approved" : "Unapproved"}
          </span>
          <span className="font-medium text-gray-700">{e.measureName}</span>
          <span className="text-gray-400">·</span>
          <span className="text-gray-500">
            {e.actedByName ?? e.actedByEmail}
          </span>
          <span className="text-gray-400">·</span>
          <span className="text-gray-400">{formatDate(e.actedAt)}</span>
        </div>
      ))}
    </div>
  );
}

async function postApprovalChanges(
  portfolioId: string,
  changes: { hubspotDealId: string; measureName: string; approved: boolean }[],
) {
  const res = await fetch(`/api/portfolio/${portfolioId}/approvals`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ changes }),
  });
  if (!res.ok) throw new Error("Failed to save approvals");
}

export default function MeasuresTable({
  data,
  userCapability,
  approvalsByDeal,
  portfolioId,
}: Props) {
  const [search, setSearch] = useState("");
  // pendingChanges: dealId -> desired Set<measureName> (the full intended approved set)
  const [pendingChanges, setPendingChanges] = useState<
    Record<string, Set<string>>
  >({});
  const [savedApprovals, setSavedApprovals] =
    useState<ApprovalsByDeal>(approvalsByDeal);
  const [showConfirm, setShowConfirm] = useState(false);
  const [expandedRows, setExpandedRows] = useState<Set<string>>(new Set());

  // Filter to only properties with proposed measures
  const dealsWithMeasures = useMemo(
    () => data.filter((d) => d.proposedMeasures),
    [data],
  );

  const filtered = useMemo(() => {
    const q = search.toLowerCase();
    if (!q) return dealsWithMeasures;
    return dealsWithMeasures.filter(
      (d) =>
        d.dealname?.toLowerCase().includes(q) ||
        d.landlordPropertyId?.toLowerCase().includes(q) ||
        d.proposedMeasures?.toLowerCase().includes(q),
    );
  }, [dealsWithMeasures, search]);

  const hasPendingChanges = Object.keys(pendingChanges).length > 0;

  // Compute diffs: for each deal in pendingChanges, what's added vs removed vs saved
  const pendingDiffs = useMemo<Record<string, PendingDiff>>(() => {
    const diffs: Record<string, PendingDiff> = {};
    for (const [dealId, pending] of Object.entries(pendingChanges)) {
      const saved = new Set(savedApprovals[dealId] ?? []);
      const added = [...pending].filter((m) => !saved.has(m));
      const removed = [...saved].filter((m) => !pending.has(m));
      if (added.length > 0 || removed.length > 0) {
        diffs[dealId] = { added, removed };
      }
    }
    return diffs;
  }, [pendingChanges, savedApprovals]);

  const dealNames = useMemo<Record<string, string>>(() => {
    const map: Record<string, string> = {};
    for (const d of dealsWithMeasures) {
      map[d.dealId] = d.dealname ?? d.landlordPropertyId ?? d.dealId;
    }
    return map;
  }, [dealsWithMeasures]);

  const saveMutation = useMutation({
    mutationFn: () => {
      // Build flat list of explicit changes from diffs
      const changes: { hubspotDealId: string; measureName: string; approved: boolean }[] = [];
      for (const [dealId, diff] of Object.entries(pendingDiffs)) {
        for (const m of diff.added) changes.push({ hubspotDealId: dealId, measureName: m, approved: true });
        for (const m of diff.removed) changes.push({ hubspotDealId: dealId, measureName: m, approved: false });
      }
      return postApprovalChanges(portfolioId, changes);
    },
    onSuccess: () => {
      setSavedApprovals((prev) => {
        const next = { ...prev };
        for (const [dealId, pending] of Object.entries(pendingChanges)) {
          next[dealId] = Array.from(pending);
        }
        return next;
      });
      setPendingChanges({});
      setShowConfirm(false);
    },
  });

  function toggleMeasure(dealId: string, measure: string) {
    setPendingChanges((prev) => {
      const base =
        prev[dealId] !== undefined
          ? new Set(prev[dealId])
          : new Set(savedApprovals[dealId] ?? []);

      if (base.has(measure)) {
        base.delete(measure);
      } else {
        base.add(measure);
      }

      // If pending equals saved, remove from tracking
      const saved = new Set(savedApprovals[dealId] ?? []);
      const equal = base.size === saved.size && [...base].every((m) => saved.has(m));

      const next = { ...prev };
      if (equal) {
        delete next[dealId];
      } else {
        next[dealId] = base;
      }
      return next;
    });
  }

  function toggleRowExpand(dealId: string) {
    setExpandedRows((prev) => {
      const next = new Set(prev);
      if (next.has(dealId)) next.delete(dealId);
      else next.add(dealId);
      return next;
    });
  }

  if (dealsWithMeasures.length === 0) {
    return (
      <div className="rounded-xl border border-gray-100 bg-white p-12 text-center">
        <p className="text-sm text-gray-400">
          No properties with proposed measures found in this project.
        </p>
      </div>
    );
  }

  return (
    <div className="space-y-4">
      {/* Toolbar */}
      <div className="flex items-center justify-between gap-3 flex-wrap">
        <div className="relative flex-1 min-w-48 max-w-sm">
          <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" />
          <Input
            placeholder="Search address or measure…"
            value={search}
            onChange={(e) => setSearch(e.target.value)}
            className="pl-9 h-9 text-sm"
          />
        </div>
        <div className="flex items-center gap-2">
          <span className="text-xs text-gray-400">
            {filtered.length} of {dealsWithMeasures.length} properties
          </span>
          {userCapability.includes("approver") && hasPendingChanges && (
            <Button
              size="sm"
              onClick={() => setShowConfirm(true)}
              className="bg-brandblue text-white gap-1.5"
            >
              <Save className="h-3.5 w-3.5" />
              Review changes ({Object.keys(pendingDiffs).length})
            </Button>
          )}
        </div>
      </div>

      {/* Table */}
      <div className="rounded-xl border border-gray-100 overflow-hidden bg-white">
        <Table>
          <TableHeader>
            <TableRow className="bg-gray-50 border-b border-gray-100">
              <TableHead className="w-6" />
              <TableHead className="text-xs font-semibold text-gray-500 uppercase tracking-wide">
                Address
              </TableHead>
              <TableHead className="text-xs font-semibold text-gray-500 uppercase tracking-wide">
                Stage
              </TableHead>
              <TableHead className="text-xs font-semibold text-gray-500 uppercase tracking-wide">
                Proposed Measures
              </TableHead>
              <TableHead className="text-xs font-semibold text-gray-500 uppercase tracking-wide">
                Status
              </TableHead>
            </TableRow>
          </TableHeader>
          <TableBody>
            {filtered.map((deal) => {
              const proposed = parseMeasures(deal.proposedMeasures);
              const approvedForDeal =
                pendingChanges[deal.dealId] !== undefined
                  ? Array.from(pendingChanges[deal.dealId])
                  : (savedApprovals[deal.dealId] ?? []);
              const approvedSet = new Set(approvedForDeal);
              const stageColor = STAGE_COLORS[deal.displayStage];
              const hasPending = pendingChanges[deal.dealId] !== undefined;
              const isExpanded = expandedRows.has(deal.dealId);

              return (
                <React.Fragment key={deal.dealId}>
                  <TableRow
                    className={`border-b border-gray-50 hover:bg-gray-50/50 transition-colors ${hasPending ? "bg-amber-50/30" : ""}`}
                  >
                    {/* Expand toggle */}
                    <TableCell className="py-3 pl-3 pr-0 w-6">
                      <button
                        onClick={() => toggleRowExpand(deal.dealId)}
                        className="text-gray-400 hover:text-brandblue transition-colors"
                        aria-label={isExpanded ? "Collapse activity" : "Expand activity"}
                      >
                        {isExpanded ? (
                          <ChevronDown className="h-4 w-4" />
                        ) : (
                          <ChevronRight className="h-4 w-4" />
                        )}
                      </button>
                    </TableCell>

                    {/* Address */}
                    <TableCell className="py-3">
                      <div className="font-medium text-sm text-gray-800">
                        {deal.dealname ?? "—"}
                      </div>
                      {deal.landlordPropertyId && (
                        <div className="text-xs text-gray-400 mt-0.5">
                          {deal.landlordPropertyId}
                        </div>
                      )}
                    </TableCell>

                    {/* Stage */}
                    <TableCell className="py-3">
                      <span
                        className={`inline-flex items-center gap-1.5 px-2 py-1 rounded-full text-xs font-medium border ${stageColor.bg} ${stageColor.text} ${stageColor.border}`}
                      >
                        <span className={`h-1.5 w-1.5 rounded-full ${stageColor.dot}`} />
                        {deal.displayStage}
                      </span>
                    </TableCell>

                    {/* Proposed measures */}
                    <TableCell className="py-3">
                      <div className="flex flex-wrap gap-1.5">
                        {proposed.map((measure) => {
                          const isApproved = approvedSet.has(measure);
                          if (userCapability.includes("approver")) {
                            return (
                              <label
                                key={measure}
                                className={`flex items-center gap-1.5 cursor-pointer px-2 py-1 rounded-full text-xs border transition-colors ${
                                  isApproved
                                    ? "bg-emerald-50 border-emerald-200 text-emerald-700"
                                    : "bg-gray-50 border-gray-200 text-gray-600 hover:bg-gray-100"
                                }`}
                              >
                                <Checkbox
                                  checked={isApproved}
                                  onCheckedChange={() => toggleMeasure(deal.dealId, measure)}
                                  className="h-3 w-3"
                                />
                                {measure}
                              </label>
                            );
                          }
                          return (
                            <span
                              key={measure}
                              className={`px-2 py-1 rounded-full text-xs border ${
                                isApproved
                                  ? "bg-emerald-50 border-emerald-200 text-emerald-700"
                                  : "bg-gray-50 border-gray-200 text-gray-600"
                              }`}
                            >
                              {measure}
                            </span>
                          );
                        })}
                      </div>
                    </TableCell>

                    {/* Status */}
                    <TableCell className="py-3">
                      <ApprovalStatus proposed={proposed} approved={approvedForDeal} />
                    </TableCell>

                  </TableRow>

                  {/* Expandable activity log row */}
                  {isExpanded && (
                    <TableRow className="bg-gray-50/50">
                      <TableCell
                        colSpan={5}
                        className="p-0"
                      >
                        <div className="border-t border-gray-100">
                          <p className="text-xs font-semibold text-gray-400 uppercase tracking-wide px-4 pt-2 pb-1">
                            Activity log
                          </p>
                          <ActivityLog dealId={deal.dealId} portfolioId={portfolioId} />
                        </div>
                      </TableCell>
                    </TableRow>
                  )}
                </React.Fragment>
              );
            })}
          </TableBody>
        </Table>
      </div>

      {/* Confirmation dialog */}
      <ApprovalConfirmDialog
        open={showConfirm}
        pendingDiffs={pendingDiffs}
        dealNames={dealNames}
        onConfirm={() => saveMutation.mutate()}
        onCancel={() => setShowConfirm(false)}
        isPending={saveMutation.isPending}
      />

    </div>
  );
}
