"use client";

import { useCallback, useEffect, useState } from "react";
import { customerApi } from "@/lib/api/customer";
import { ApiException } from "@/lib/api/client";
import { identityErrors } from "@/lib/validation";
import { useToken } from "@/lib/auth/useToken";
import { usePincodeLookup } from "@/lib/hooks/usePincodeLookup";
import type { ApiAddress } from "@/lib/api/types";
import { MapPin, Plus, Trash2, Pencil, X } from "lucide-react";
import ConfirmDialog from "@/components/ui/ConfirmDialog";
import { formatDateShort } from "@/lib/utils";

type FormState = Partial<ApiAddress> & { id?: number };

const empty: FormState = { country: "India" };

function createdLabel(value: string | null) {
  if (!value) return "Recently added";
  const label = formatDateShort(value);
  return label === "—" ? "Recently added" : label;
}

function DetailRow({ label, value }: { label: string; value: string }) {
  return (
    <div className="grid grid-cols-[132px_1fr] items-start gap-3 border-b border-gray-100 py-2.5 last:border-b-0">
      <p className="text-xs font-semibold uppercase tracking-wide text-gray-500">{label}</p>
      <p className="text-sm text-gray-800 break-words">{value}</p>
    </div>
  );
}

/**
 * The address book is one interactive unit — "Edit" on a card populates the
 * same form the "Add" button toggles, and the pincode field drives a live
 * lookup — so it stays a client component rather than being split apart.
 *
 * What did move to the server is the *initial* read: the page above fetches the
 * list during SSR and seeds it here via `initialList`. That removes the
 * hydrate-then-fetch waterfall; the cards are in the first HTML response and
 * there is no loading spinner on first paint. Subsequent reloads after a
 * mutation still go through the client, which is fine — by then the bundle is
 * already warm.
 */
export default function AddressesManager({ initialList }: { initialList: ApiAddress[] }) {
  const { token } = useToken();
  const [list, setList] = useState<ApiAddress[]>(initialList);
  const [form, setForm] = useState<FormState>(empty);
  const [errors, setErrors] = useState<Record<string, string[]>>({});
  const [saving, setSaving] = useState(false);
  const [showForm, setShowForm] = useState(false);
  const [pendingDelete, setPendingDelete] = useState<ApiAddress | null>(null);

  const load = useCallback(() => {
    if (!token) return;
    customerApi.addresses(token).then((r) => setList(r.data));
  }, [token]);

  const pincodeLookup = usePincodeLookup((form.pincode as string) ?? "");
  useEffect(() => {
    if (!pincodeLookup.data) return;
    setForm((prev) => ({
      ...prev,
      city: prev.city || pincodeLookup.data!.city,
      state: prev.state || pincodeLookup.data!.state,
      country: prev.country || pincodeLookup.data!.country,
    }));
  }, [pincodeLookup.data]);

  const onSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!token) return;
    // Pincode, phone and GSTIN checked like the API does (B32).
    const pre = identityErrors(form as Record<string, unknown>);
    if (Object.keys(pre).length > 0) {
      setErrors(pre);
      return;
    }
    setSaving(true);
    setErrors({});
    try {
      if (form.id) {
        await customerApi.updateAddress(token, form.id, form);
      } else {
        await customerApi.createAddress(token, form);
      }
      setForm(empty);
      setShowForm(false);
      load();
    } catch (e) {
      if (e instanceof ApiException && e.errors) setErrors(e.errors);
    } finally {
      setSaving(false);
    }
  };

  const onDelete = async (id: number) => {
    if (!token) return;
    await customerApi.deleteAddress(token, id);
    setPendingDelete(null);
    load();
  };

  const onEdit = (a: ApiAddress) => {
    setForm({ ...a });
    setShowForm(true);
  };

  const f = (key: keyof FormState, label: string, required = false) => (
    <div>
      <label className="mb-1 block text-xs font-medium text-gray-700">
        {label}{required && <span className="text-red-500"> *</span>}
      </label>
      <input
        type="text"
        value={(form[key] as string) ?? ""}
        placeholder={`Enter ${label.toLowerCase()}`}
        onChange={(e) => setForm({ ...form, [key]: e.target.value })}
        className="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm focus:border-[#CC1414] focus:outline-none focus:ring-1 focus:ring-[#CC1414]"
      />
      {errors[key] && <p className="mt-1 text-xs text-red-600">{errors[key][0]}</p>}
    </div>
  );

  return (
    <div className="space-y-4">
      <div className="flex items-center justify-between">
        <h1 className="text-2xl font-bold text-gray-900">Addresses</h1>
        <button
          onClick={() => { setForm(empty); setShowForm((s) => !s); }}
          className="flex items-center gap-2 rounded-lg bg-[#CC1414] px-4 py-2 text-sm font-medium text-white hover:bg-[#a30f0f]"
        >
          {showForm ? <X className="h-4 w-4" /> : <Plus className="h-4 w-4" />}
          {showForm ? "Cancel" : "Add Address"}
        </button>
      </div>

      {showForm && (
        <form onSubmit={onSubmit} className="rounded-xl bg-white p-6 shadow-sm ring-1 ring-gray-100">
          <div className="grid grid-cols-1 gap-4 md:grid-cols-2">
            {f("address_line_one", "Address Line 1", true)}
            {f("address_line_two", "Address Line 2")}
            <div>
              <label className="mb-1 block text-xs font-medium text-gray-700">
                Pincode<span className="text-red-500"> *</span>
              </label>
              <input
                type="text"
                inputMode="numeric"
                maxLength={6}
                placeholder="Enter 6-digit pincode"
                value={(form.pincode as string) ?? ""}
                onChange={(e) =>
                  setForm({ ...form, pincode: e.target.value.replace(/\D/g, "").slice(0, 6) })
                }
                className="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm focus:border-[#CC1414] focus:outline-none focus:ring-1 focus:ring-[#CC1414]"
              />
              {pincodeLookup.loading && (
                <p className="mt-1 text-xs text-gray-500">Looking up pincode…</p>
              )}
              {pincodeLookup.error && (
                <p className="mt-1 text-xs text-amber-600">{pincodeLookup.error}</p>
              )}
              {errors.pincode && <p className="mt-1 text-xs text-red-600">{errors.pincode[0]}</p>}
            </div>
            {f("city", "City", true)}
            {f("state", "State", true)}
            {f("country", "Country")}
            {f("company_name", "Company Name")}
            {f("phone", "Phone", true)}
            {f("gst", "GST Number")}
          </div>
          <div className="mt-5 flex justify-end gap-2">
            <button
              type="submit"
              disabled={saving}
              className="rounded-lg bg-[#CC1414] px-5 py-2 text-sm font-medium text-white hover:bg-[#a30f0f] disabled:opacity-60"
            >
              {saving ? "Saving…" : form.id ? "Update" : "Save"}
            </button>
          </div>
        </form>
      )}

      {!showForm && list.length === 0 ? (
        <div className="rounded-xl bg-white p-8 text-center text-gray-500 shadow-sm ring-1 ring-gray-100">
          <MapPin className="mx-auto mb-2 h-8 w-8 text-gray-400" />
          No addresses saved yet.
        </div>
      ) : !showForm ? (
        <div className="grid grid-cols-1 gap-4 md:grid-cols-2">
          {list.map((a, idx) => (
            <div key={a.id} className="rounded-2xl bg-white p-5 shadow-sm ring-1 ring-gray-100 transition hover:shadow-md hover:ring-gray-200">
              <div className="flex items-start justify-between gap-4">
                <div className="min-w-0">
                  <h3 className="truncate text-base font-semibold text-gray-900">
                    {a.company_name?.trim() || `Saved Address ${idx + 1}`}
                  </h3>
                  <p className="mt-1 text-xs text-gray-500">Address ID: #{a.id}</p>
                </div>
                <div className="flex items-center gap-2">
                  <button
                    onClick={() => onEdit(a)}
                    className="inline-flex items-center gap-1 rounded-md border border-gray-200 px-3 py-2 text-xs font-medium text-gray-700 hover:bg-gray-50"
                    aria-label="Edit address"
                  >
                    <Pencil className="h-3.5 w-3.5" /> Edit
                  </button>
                  <button
                    onClick={() => setPendingDelete(a)}
                    className="inline-flex items-center gap-1 rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs font-medium text-red-700 hover:bg-red-100"
                    aria-label="Delete address"
                  >
                    <Trash2 className="h-3.5 w-3.5" /> Delete
                  </button>
                </div>
              </div>

              <div className="mt-4 rounded-xl bg-gray-50 p-4 ring-1 ring-gray-100">
                <DetailRow label="Company" value={a.company_name?.trim() || "Not provided"} />
                <DetailRow label="Phone" value={a.phone || "Not provided"} />
                <DetailRow label="GST Number" value={a.gst?.trim() || "Not provided"} />
                <DetailRow label="Address Line 1" value={a.address_line_one || "Not provided"} />
                <DetailRow label="Address Line 2" value={a.address_line_two?.trim() || "Not provided"} />
                <DetailRow label="City" value={a.city || "Not provided"} />
                <DetailRow label="State" value={a.state || "Not provided"} />
                <DetailRow label="Pincode" value={a.pincode || "Not provided"} />
                <DetailRow label="Country" value={a.country || "Not provided"} />
                <DetailRow label="Added On" value={createdLabel(a.created_at)} />
              </div>
            </div>
          ))}
        </div>
      ) : null}

      <ConfirmDialog
        open={!!pendingDelete}
        title="Delete this address?"
        description="This saved address will be removed from your account."
        confirmLabel="Delete"
        onCancel={() => setPendingDelete(null)}
        onConfirm={() => {
          if (pendingDelete) onDelete(pendingDelete.id);
        }}
      />
    </div>
  );
}
