"use client";

import { Column, ColumnDef } from "@tanstack/react-table";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/app/shadcn_components/ui/dropdown-menu";
import { Button } from "@/app/shadcn_components/ui/button";
import { ArrowUpDown, MoreHorizontal } from "lucide-react";
import { FunnelIcon } from "@heroicons/react/24/outline";
import { formatNumber, getEpcColorClass, sapToEpc } from "@/app/utils";
import { cn } from "@/lib/utils";
import { PropertyWithRelations } from "@/app/db/schema/property";
import { expectedEpcRating } from "./expectedEpc";
import { X } from "lucide-react";
import { EnumOption, MAINFUEL_OPTIONS } from "@/app/utils/propertyFilters";
import { CurrentEpcTooltip } from "./CurrentEpcTooltip";
import { TagsCell } from "./TagsCell";
import { Checkbox } from "@/app/shadcn_components/ui/checkbox";

/* -----------------------------------------------------------------------
   Helpers
------------------------------------------------------------------------ */
function resolveEnumLabel(
  options: EnumOption[],
  dbValue: string | null | undefined
): string | null {
  if (dbValue == null) return null;
  const opt = options.find((o) => o.dbValues.includes(dbValue));
  return opt?.label ?? dbValue;
}

function Pill({
  children,
  className = "bg-slate-100 text-slate-600",
}: {
  children: React.ReactNode;
  className?: string;
}) {
  return (
    <span
      className={`inline-block px-2 py-0.5 rounded text-[9px] font-bold uppercase tracking-wide whitespace-nowrap ${className}`}
    >
      {children}
    </span>
  );
}

/* -----------------------------------------------------------------------
   EPC letter bubble
------------------------------------------------------------------------ */
/**
 * The one treatment for an absent value across the table (ADR-0013 impeccable
 * pass): a single quiet, AA-legible em-dash with an accessible label — replacing
 * the four different empty renderings (blank div, slate-300 "—", italic
 * "No cost", "Unknown") the critique flagged.
 */
const EmptyCell = ({ label = "No data" }: { label?: string }) => (
  <span className="text-slate-400" title={label} aria-label={label}>
    —
  </span>
);

const EpcLetterBubble = ({ letter }: { letter: string }) => {
  if (!letter)
    return (
      <div
        className="inline-flex h-5 w-5 items-center justify-center rounded-full border border-slate-200 text-[11px] font-semibold text-slate-400"
        title="No rating yet"
        aria-label="No rating yet"
      >
        –
      </div>
    );
  return (
    <div
      className={`inline-flex items-center justify-center w-5 h-5 rounded-full text-xs font-bold text-white ${getEpcColorClass(letter)}`}
    >
      {letter}
    </div>
  );
};

/**
 * Marks a property whose EPC was estimated from nearby homes (no certificate) —
 * the "trust this less" signal. Re-modelled properties aren't marked (the
 * Lodged-EPC column differing from Current already conveys that). See ADR-0002.
 */
const PredictedPill = () => (
  <span
    className="inline-flex items-center rounded-full bg-amber-100 px-1.5 py-0.5 text-[9px] font-bold uppercase tracking-wide text-amber-700 border border-amber-200"
    title="Estimated from nearby homes — no EPC certificate on record"
  >
    Predicted
  </span>
);

/* -----------------------------------------------------------------------
   Column header with dropdown filter
------------------------------------------------------------------------ */
interface DataTableColumnHeaderProps<TData, TValue>
  extends React.HTMLAttributes<HTMLDivElement> {
  column: Column<TData, TValue>;
  title: string;
}

export function DataTableFilterHeader<TData, TValue>({
  column,
  title,
  className,
  options,
  renderOption,
}: DataTableColumnHeaderProps<TData, TValue> & {
  options: string[];
  renderOption?: (opt: string) => React.ReactNode;
}) {
  const currentValue = column.getFilterValue() as string | undefined;

  return (
    <div className={cn("flex items-center space-x-1", className)}>
      <DropdownMenu>
        <DropdownMenuTrigger asChild>
          <Button
            variant={currentValue ? "secondary" : "ghost"}
            size="sm"
            className={cn(
              "-ml-2 h-8",
              currentValue && "text-accent-foreground bg-accent"
            )}
          >
            <span>{title}</span>
            <FunnelIcon className="ml-2 h-4 w-4" />
          </Button>
        </DropdownMenuTrigger>
        <DropdownMenuContent
          align="start"
          className="max-h-80 overflow-y-auto min-w-[10rem]"
        >
          {options.map((opt) => (
            <DropdownMenuItem
              key={opt}
              onClick={() =>
                column.setFilterValue(currentValue === opt ? undefined : opt)
              }
              className={cn(
                "cursor-pointer flex items-center gap-2 px-2 py-1.5",
                currentValue === opt && "bg-accent"
              )}
            >
              {renderOption ? renderOption(opt) : opt}
            </DropdownMenuItem>
          ))}
        </DropdownMenuContent>
      </DropdownMenu>

      {currentValue && (
        <Button
          variant="ghost"
          className={cn(
            "h-6 w-6 text-gray-500 hover:text-gray-800 transition-opacity duration-150",
            currentValue ? "opacity-100" : "opacity-0 pointer-events-none"
          )}
          onClick={() => column.setFilterValue(undefined)}
          title="Clear filter"
        >
          <X className="h-3.5 w-3.5" />
        </Button>
      )}
    </div>
  );
}

/* -----------------------------------------------------------------------
   Column metadata
------------------------------------------------------------------------ */
export const OPTIONAL_COLUMN_IDS = [
  "tags",
  "propertyType",
  "builtForm",
  "yearBuilt",
  "totalFloorArea",
  "co2Emissions",
  "mainfuel",
  "wallType",
  "roofType",
  "heatingSystem",
] as const;

export type OptionalColumnId = (typeof OPTIONAL_COLUMN_IDS)[number];

const OPTIONAL_COLUMN_LABELS: Record<OptionalColumnId, string> = {
  tags: "Tags",
  propertyType: "Property Type",
  builtForm: "Built Form",
  yearBuilt: "Construction Age",
  totalFloorArea: "Floor Area (m²)",
  co2Emissions: "CO₂ Emissions",
  mainfuel: "Main Fuel",
  wallType: "Wall Type",
  roofType: "Roof Type",
  heatingSystem: "Heating System",
};

export { OPTIONAL_COLUMN_LABELS };

/* -----------------------------------------------------------------------
   Core columns
------------------------------------------------------------------------ */
const coreColumns: ColumnDef<PropertyWithRelations>[] = [
  {
    id: "select",
    enableSorting: false,
    enableHiding: false,
    // Selects ALL loaded rows (not just the paginated page), so on a small page
    // size it still covers everything in view. When more properties match than
    // are loaded, the TagActionBar offers "Select all N matching" on top of this.
    header: ({ table }) => (
      <Checkbox
        aria-label="Select all loaded rows"
        checked={
          table.getIsAllRowsSelected()
            ? true
            : table.getIsSomeRowsSelected()
              ? "indeterminate"
              : false
        }
        onCheckedChange={(v) => table.toggleAllRowsSelected(!!v)}
      />
    ),
    cell: ({ row }) => (
      <Checkbox
        aria-label="Select row"
        checked={row.getIsSelected()}
        onCheckedChange={(v) => row.toggleSelected(!!v)}
      />
    ),
  },
  {
    accessorKey: "address",
    enableGlobalFilter: true,
    header: ({ column }) => (
      <Button
        variant="ghost"
        onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
      >
        Address
        <ArrowUpDown className="ml-2 h-4 w-4" />
      </Button>
    ),
    cell: ({ row }) => {
      const address = String(row.getValue("address"));
      const postcode = row.original.postcode;
      const propertyId = row.original.id;
      const portfolioId = row.original.portfolioId;

      return (
        <div className="flex flex-col gap-0.5">
          <a
            href={`${portfolioId}/building-passport/${propertyId}`}
            className="text-xs font-bold text-primary hover:text-brandmidblue transition-colors truncate"
          >
            {address}
          </a>
          {postcode && (
            <span className="text-[10px] text-slate-400">{postcode}</span>
          )}
        </div>
      );
    },
  },
  {
    accessorKey: "landlordPropertyId",
    header: () => <div className="text-xs font-medium">Property Ref</div>,
    cell: ({ row }) => (
      <div className="text-gray-700 text-sm">
        {row.original.landlordPropertyId ?? <EmptyCell />}
      </div>
    ),
  },
  {
    id: "tags",
    // Toggle-able (in OPTIONAL_COLUMN_IDS) but default-visible — see PropertyTable.
    // Not sortable/filterable here; the tags filter lives in PropertyFilters.
    enableSorting: false,
    header: () => <div className="text-xs">Tags</div>,
    cell: ({ row }) => <TagsCell property={row.original} />,
  },
  {
    accessorKey: "currentEpc",
    header: () => (
      <div className="flex items-center justify-center gap-1 text-xs">
        Current EPC
        <CurrentEpcTooltip />
      </div>
    ),
    cell: ({ row }) => (
      <div className="text-gray-700 font-medium flex items-center justify-center gap-1.5">
        <EpcLetterBubble letter={row.original.currentEpcRating || ""} />
        {row.original.provenanceSignal === "estimated" && <PredictedPill />}
      </div>
    ),
  },
  {
    accessorKey: "lodgedEpcRating",
    header: () => (
      <div className="flex justify-center text-xs">Lodged EPC</div>
    ),
    cell: ({ row }) => {
      // Effective is the "current"; this column shows the real lodged
      // certificate, blank when there is none (predicted properties). For legacy
      // rows the query returns the row's rating; new-approach returns lodged or
      // NULL. originalSapPoints remains a fallback for legacy rows lacking a band.
      const letter =
        row.original.lodgedEpcRating ??
        (row.original.originalSapPoints
          ? sapToEpc(row.original.originalSapPoints)
          : null);
      return (
        <div className="text-gray-700 font-medium flex justify-center">
          <EpcLetterBubble letter={letter || ""} />
        </div>
      );
    },
  },
  {
    accessorKey: "targetEpc",
    header: () => (
      <div className="flex justify-center text-xs">Expected EPC</div>
    ),
    cell: ({ row }) => {
      const expectedEpc = expectedEpcRating(
        row.original.postEpcRating != null || row.original.postSapPoints != null
          ? {
              postEpcRating: row.original.postEpcRating,
              postSapPoints: row.original.postSapPoints,
            }
          : null,
      );
      return (
        <div className="text-gray-700 font-medium flex justify-center">
          <EpcLetterBubble letter={expectedEpc} />
        </div>
      );
    },
  },
  {
    accessorKey: "epcLodgementDate",
    header: () => (
      <div className="flex justify-center text-xs">EPC Expiry</div>
    ),
    cell: ({ row }) => {
      const dateStr = row.original.epcLodgementDate;
      const expired = row.original.epcIsExpired;

      if (!dateStr) {
        return (
          <div className="flex justify-center">
            <EmptyCell label="No expiry date" />
          </div>
        );
      }

      const lodgementDate = new Date(dateStr);
      const expiryDate = new Date(lodgementDate);
      expiryDate.setFullYear(expiryDate.getFullYear() + 10);

      const formatted = expiryDate.toLocaleDateString("en-GB", {
        month: "short",
        year: "numeric",
      });

      if (expired) {
        return (
          <div className="flex flex-col gap-0.5">
            <span className="text-[9px] font-bold text-red-600 bg-red-50 px-1.5 py-0.5 rounded w-max uppercase tracking-wide">
              Expired
            </span>
            <span className="text-[10px] text-slate-400">{formatted}</span>
          </div>
        );
      }

      return (
        <div className="flex flex-col gap-0.5">
          <span className="text-xs font-semibold text-primary">{formatted}</span>
        </div>
      );
    },
  },
  {
    accessorKey: "cost",
    header: () => <div className="flex justify-end text-xs">Plan Cost</div>,
    cell: ({ row }) => {
      const cost = row.original.totalRecommendationCost;
      const creationStatus = row.original.creationStatus;

      if (creationStatus === "LOADING") {
        return <div className="font-medium flex justify-end" />;
      }

      return (
        <div className="flex justify-end text-right">
          {cost ? (
            <span className="text-xs font-bold text-primary">
              £{formatNumber(cost)}
            </span>
          ) : (
            <EmptyCell label="Not modelled yet" />
          )}
        </div>
      );
    },
  },
  {
    id: "actions",
    cell: ({ row }) => {
      const property = row.original;
      const propertyId = property.id;
      const portfolioId = property.portfolioId;
      const creationStatus = property.creationStatus;

      if (creationStatus === "LOADING") {
        return (
          <div className="text-gray-700 flex justify-center">Loading...</div>
        );
      }

      return (
        <div className="flex justify-center">
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button variant="ghost" className="h-8 w-8 p-0">
                <span className="sr-only">Open menu</span>
                <MoreHorizontal className="h-4 w-4" />
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="end">
              <DropdownMenuLabel>Actions</DropdownMenuLabel>
              <DropdownMenuItem className="text-gray-700 cursor-pointer">
                <a href={`${portfolioId}/building-passport/${propertyId}`}>
                  Building Passport
                </a>
              </DropdownMenuItem>
              <DropdownMenuItem className="text-gray-700 cursor-pointer">
                Settings
              </DropdownMenuItem>
              <DropdownMenuSeparator />
            </DropdownMenuContent>
          </DropdownMenu>
        </div>
      );
    },
  },
];

/* -----------------------------------------------------------------------
   Optional columns
------------------------------------------------------------------------ */
const optionalColumns: ColumnDef<PropertyWithRelations>[] = [
  {
    id: "propertyType",
    accessorKey: "propertyType",
    header: () => <div className="text-xs">Property Type</div>,
    cell: ({ row }) => {
      const val = row.original.propertyType;
      return val ? <Pill>{val}</Pill> : <EmptyCell />;
    },
  },
  {
    id: "builtForm",
    accessorKey: "builtForm",
    header: () => <div className="text-xs">Built Form</div>,
    cell: ({ row }) => {
      const val = row.original.builtForm;
      return val ? <Pill>{val}</Pill> : <EmptyCell />;
    },
  },
  {
    id: "yearBuilt",
    accessorKey: "yearBuilt",
    header: () => <div className="text-xs">Construction Age</div>,
    cell: ({ row }) => (
      <div className="text-sm text-gray-700">
        {row.original.yearBuilt ?? <EmptyCell />}
      </div>
    ),
  },
  {
    id: "totalFloorArea",
    accessorKey: "totalFloorArea",
    header: () => <div className="text-xs">Floor Area (m²)</div>,
    cell: ({ row }) => {
      const val = row.original.totalFloorArea;
      return (
        <div className="text-sm text-gray-700">
          {val != null ? `${val.toFixed(1)} m²` : <EmptyCell />}
        </div>
      );
    },
  },
  {
    id: "co2Emissions",
    accessorKey: "co2Emissions",
    header: () => <div className="text-xs">CO₂ Emissions</div>,
    cell: ({ row }) => {
      const val = row.original.co2Emissions;
      return (
        <div className="text-sm text-gray-700">
          {val != null ? `${val.toFixed(1)} kg/m²/yr` : <EmptyCell />}
        </div>
      );
    },
  },
  {
    id: "mainfuel",
    accessorKey: "mainfuel",
    header: () => <div className="text-xs">Main Fuel</div>,
    cell: ({ row }) => {
      const label = resolveEnumLabel(MAINFUEL_OPTIONS, row.original.mainfuel);
      return label ? <Pill>{label}</Pill> : <EmptyCell />;
    },
  },
  {
    id: "wallType",
    accessorKey: "wallType",
    header: () => <div className="text-xs">Wall Type</div>,
    cell: ({ row }) => <DescriptorCell value={row.original.wallType} />,
  },
  {
    id: "roofType",
    accessorKey: "roofType",
    header: () => <div className="text-xs">Roof Type</div>,
    cell: ({ row }) => <DescriptorCell value={row.original.roofType} />,
  },
  {
    id: "heatingSystem",
    accessorKey: "heatingSystem",
    header: () => <div className="text-xs">Heating System</div>,
    cell: ({ row }) => <DescriptorCell value={row.original.heatingSystem} />,
  },
];

/** Long free-text descriptor (wall/roof/heating): truncate with a full-value tooltip; muted when Unknown. */
function DescriptorCell({ value }: { value: string | null }) {
  const val = value ?? "Unknown";
  return (
    <div
      className={cn(
        "text-sm max-w-[220px] truncate",
        val === "Unknown" ? "text-slate-500" : "text-gray-700",
      )}
      title={val}
    >
      {val}
    </div>
  );
}

export const columns: ColumnDef<PropertyWithRelations>[] = [
  ...coreColumns,
  ...optionalColumns,
];

// The same columns without the leading selection checkbox — row-select is only
// shown while bulk-tagging (ADR-0013 impeccable pass), so the default table has
// no persistent checkbox column. Precomputed (stable identity, no useMemo).
export const columnsWithoutSelect: ColumnDef<PropertyWithRelations>[] =
  columns.filter((c) => c.id !== "select");
