"use client";

import { useState } from "react";
import { MagnifyingGlassIcon, CheckCircleIcon } from "@heroicons/react/24/outline";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
  DialogFooter,
} from "@/app/shadcn_components/ui/dialog";
import { describeCandidate } from "@/lib/postcodeSearch/model";
import { searchAddresses, type SearchCandidate } from "@/lib/properties/client";
import { useSaveUprnCorrection, type FlaggedAddress } from "@/lib/bulkUpload/client";

// The pre-finalise "Addresses" review tab (ADR-0057). Lists the combiner rows
// address2uprn could not confidently match; the user resolves each via Ordnance
// Survey (residential candidates only → a guaranteed valid UPRN) or marks it as
// having no UPRN. Confirmations are saved as corrections (keyed by
// source_row_id) and overlaid onto the combiner CSV at finalise.
export default function AddressesPanel({
  flagged,
  portfolioId,
  uploadId,
}: {
  flagged: FlaggedAddress[];
  portfolioId: string;
  uploadId: string;
}) {
  return (
    <div className="space-y-3 rounded-xl border border-amber-200 bg-amber-50/40 p-4">
      <div>
        <h3 className="text-sm font-semibold text-gray-800">
          Addresses that need a UPRN
        </h3>
        <p className="mt-0.5 text-xs text-gray-500">
          We couldn&apos;t confidently match these to Ordnance Survey. Pick the
          right address — or mark it as having no UPRN — so onboarding creates the
          correct property.
        </p>
      </div>

      {flagged.length === 0 ? (
        <p className="text-xs text-gray-400">Nothing to resolve.</p>
      ) : (
        <ul className="divide-y divide-amber-100 rounded-lg border border-amber-100 bg-white">
          {flagged.map((row) => (
            <AddressRow
              key={row.sourceRowId}
              row={row}
              portfolioId={portfolioId}
              uploadId={uploadId}
            />
          ))}
        </ul>
      )}
    </div>
  );
}

function statusLabel(status: string): string {
  switch (status) {
    case "ambiguous_duplicate":
      return "Ambiguous match";
    case "low_score":
      return "Low-confidence match";
    case "unmatched":
      return "No match";
    case "invalid_postcode":
      return "Invalid postcode";
    case "error":
      return "Match error";
    default:
      return status;
  }
}

function AddressRow({
  row,
  portfolioId,
  uploadId,
}: {
  row: FlaggedAddress;
  portfolioId: string;
  uploadId: string;
}) {
  const save = useSaveUprnCorrection(portfolioId, uploadId);
  const [open, setOpen] = useState(false);
  const [address, setAddress] = useState(row.address ?? "");
  const [postcode, setPostcode] = useState(row.postcode ?? "");
  // null = not searched yet; [] = searched, no residential matches.
  const [residential, setResidential] = useState<SearchCandidate[] | null>(null);
  const [selected, setSelected] = useState<SearchCandidate | null>(null);
  const [source, setSource] = useState<"cache" | "live" | null>(null);
  const [searching, setSearching] = useState(false);
  const [searchError, setSearchError] = useState<string | null>(null);

  async function runSearch() {
    setSearching(true);
    setSearchError(null);
    setResidential(null);
    setSelected(null);
    try {
      const result = await searchAddresses(portfolioId, postcode);
      // Residential only — we never assign a non-residential UPRN.
      setResidential(result.candidates.filter((c) => c.selectable));
      setSource(result.source);
    } catch (e) {
      setSearchError(e instanceof Error ? e.message : "Search failed.");
    } finally {
      setSearching(false);
    }
  }

  function onAssign() {
    if (!selected) return;
    save.mutate(
      {
        sourceRowId: row.sourceRowId,
        uprn: selected.uprn,
        address: selected.address,
        postcode: selected.postcode,
      },
      { onSuccess: () => setOpen(false) },
    );
  }

  function onNoUprn() {
    save.mutate({ sourceRowId: row.sourceRowId, markedNoUprn: true });
  }

  return (
    <li className="flex items-start justify-between gap-3 px-3 py-2.5">
      <div className="min-w-0 flex-1">
        <p className="truncate text-sm text-gray-800" title={row.address}>
          {row.address || "(no address)"}
        </p>
        <p className="text-[11px] text-gray-500">
          {row.postcode || "no postcode"}
          {row.lexiscore != null ? ` · score ${row.lexiscore.toFixed(2)}` : ""}
          {" · "}
          <span className="font-medium text-amber-700">{statusLabel(row.status)}</span>
        </p>
        {row.resolved && (
          <p className="mt-1 inline-flex items-center gap-1 text-[11px] font-medium text-green-700">
            <CheckCircleIcon className="h-3.5 w-3.5" />
            {row.markedNoUprn
              ? "Marked: no UPRN"
              : `UPRN ${row.resolvedUprn}${row.resolvedAddress ? ` · ${row.resolvedAddress}` : ""}`}
          </p>
        )}
      </div>

      <div className="flex shrink-0 items-center gap-2">
        {row.resolved ? (
          <button
            type="button"
            onClick={() => setOpen(true)}
            className="text-xs text-gray-500 underline underline-offset-2 hover:text-gray-800"
          >
            Change
          </button>
        ) : (
          <>
            <button
              type="button"
              onClick={() => setOpen(true)}
              className="inline-flex items-center gap-1.5 rounded-lg border border-amber-300 bg-white px-3 py-1.5 text-xs font-semibold text-amber-800 transition-colors hover:bg-amber-100"
            >
              <MagnifyingGlassIcon className="h-3.5 w-3.5" />
              Find UPRN
            </button>
            <button
              type="button"
              onClick={onNoUprn}
              disabled={save.isPending}
              className="text-xs text-gray-500 underline underline-offset-2 hover:text-gray-800 disabled:cursor-not-allowed disabled:opacity-50"
            >
              No UPRN
            </button>
          </>
        )}
      </div>

      <Dialog open={open} onOpenChange={setOpen}>
        <DialogContent className="max-w-lg">
          <DialogHeader>
            <DialogTitle>Match to a UPRN</DialogTitle>
            <DialogDescription>
              Confirm the postcode and pick the matching address. Only residential
              addresses from Ordnance Survey are shown, so the UPRN is always valid.
            </DialogDescription>
          </DialogHeader>

          <div className="space-y-3">
            <div>
              <label className="mb-1 block text-xs font-semibold text-gray-600">
                Address
              </label>
              <input
                value={address}
                onChange={(e) => setAddress(e.target.value)}
                placeholder="e.g. 20 Brenchley Road"
                className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:border-amber-400 focus:outline-none focus:ring-1 focus:ring-amber-400"
              />
            </div>
            <div className="flex items-end gap-2">
              <div className="flex-1">
                <label className="mb-1 block text-xs font-semibold text-gray-600">
                  Postcode
                </label>
                <input
                  value={postcode}
                  onChange={(e) => setPostcode(e.target.value)}
                  placeholder="e.g. BR5 2TD"
                  onKeyDown={(e) => {
                    if (e.key === "Enter" && postcode.trim() && !searching)
                      runSearch();
                  }}
                  className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm uppercase focus:border-amber-400 focus:outline-none focus:ring-1 focus:ring-amber-400"
                />
              </div>
              <button
                type="button"
                onClick={runSearch}
                disabled={!postcode.trim() || searching}
                className="inline-flex items-center gap-1.5 rounded-lg bg-amber-600 px-4 py-2 text-sm font-semibold text-white transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:bg-amber-300"
              >
                <MagnifyingGlassIcon className="h-4 w-4" />
                {searching ? "Searching…" : "Search"}
              </button>
            </div>

            {searchError && <p className="text-xs text-red-600">{searchError}</p>}

            {residential && (
              <div>
                <div className="mb-1 flex items-center justify-between">
                  <p className="text-xs font-semibold text-gray-600">
                    Residential addresses
                  </p>
                  {source === "cache" && (
                    <span className="text-[10px] font-medium uppercase tracking-wide text-gray-400">
                      from cache
                    </span>
                  )}
                </div>
                <div className="max-h-64 overflow-y-auto rounded-lg border border-gray-100">
                  {residential.length === 0 ? (
                    <p className="px-3 py-6 text-center text-sm text-gray-400">
                      No residential addresses found for that postcode.
                    </p>
                  ) : (
                    <ul className="divide-y divide-gray-50">
                      {residential.map((c) => {
                        const { label } = describeCandidate(c);
                        const isSelected = selected?.uprn === c.uprn;
                        return (
                          <li key={c.uprn}>
                            <button
                              type="button"
                              onClick={() => setSelected(c)}
                              className={`flex w-full items-start gap-2 px-3 py-2 text-left text-sm transition-colors ${
                                isSelected ? "bg-amber-50" : "hover:bg-gray-50"
                              }`}
                            >
                              <CheckCircleIcon
                                className={`mt-0.5 h-4 w-4 shrink-0 ${
                                  isSelected ? "text-amber-600" : "text-gray-200"
                                }`}
                              />
                              <span className="min-w-0 flex-1">
                                <span
                                  className="block truncate text-gray-800"
                                  title={c.address}
                                >
                                  {c.address}
                                </span>
                                <span className="block truncate text-[11px] text-gray-500">
                                  UPRN {c.uprn} · {label}
                                  {c.alreadyInPortfolio ? " · already in portfolio" : ""}
                                </span>
                              </span>
                            </button>
                          </li>
                        );
                      })}
                    </ul>
                  )}
                </div>
              </div>
            )}
          </div>

          <DialogFooter>
            {save.error && (
              <p className="mr-auto self-center text-xs text-red-600">
                {save.error.message}
              </p>
            )}
            <button
              type="button"
              onClick={() => setOpen(false)}
              className="rounded-lg px-4 py-2 text-sm font-semibold text-gray-600 hover:bg-gray-100"
            >
              Cancel
            </button>
            <button
              type="button"
              onClick={onAssign}
              disabled={!selected || save.isPending}
              className="rounded-lg bg-amber-600 px-4 py-2 text-sm font-bold text-white transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:bg-amber-300"
            >
              {save.isPending ? "Assigning…" : "Assign UPRN"}
            </button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </li>
  );
}
