"use client";

import { useEffect, useState } from "react";
import { createPortal } from "react-dom";
import { X } from "lucide-react";
import { customerApi } from "@/lib/api/customer";
import { ApiException } from "@/lib/api/client";
import type { ApiAddress } from "@/lib/api/types";
import { usePincodeLookup } from "@/lib/hooks/usePincodeLookup";
import { identityErrors, normalizeMobile } from "@/lib/validation";
import FieldError from "@/components/ui/FieldError";

type Form = {
  company_name: string;
  gst: string;
  phone: string;
  address_line_one: string;
  address_line_two: string;
  pincode: string;
  city: string;
  state: string;
  country: string;
};

const EMPTY: Form = {
  company_name: "",
  gst: "",
  phone: "",
  address_line_one: "",
  address_line_two: "",
  pincode: "",
  city: "",
  state: "",
  country: "India",
};

/**
 * "Add new address" without leaving the form you are on (B26). Validates like
 * the API (pincode, mobile, GSTIN), fills city/state from the pincode, saves
 * to the account's address book and hands the new address back to the caller.
 */
export default function AddressFormModal({
  token,
  onClose,
  onSaved,
}: {
  token: string;
  onClose: () => void;
  onSaved: (address: ApiAddress) => void;
}) {
  const [form, setForm] = useState<Form>(EMPTY);
  const [errors, setErrors] = useState<Record<string, string[]>>({});
  const [saving, setSaving] = useState(false);
  const lookup = usePincodeLookup(form.pincode);

  useEffect(() => {
    if (!lookup.data) return;
    setForm((f) => ({
      ...f,
      city: f.city || lookup.data!.city,
      state: f.state || lookup.data!.state,
      country: f.country || lookup.data!.country,
    }));
  }, [lookup.data]);

  const set = (key: keyof Form, value: string) => {
    setForm((f) => ({ ...f, [key]: value }));
    setErrors((e) => (e[key] ? { ...e, [key]: [] } : e));
  };

  async function submit(e: React.FormEvent) {
    e.preventDefault();
    // Rendered through a portal, but React still bubbles synthetic events up
    // the component tree — without this the host page's form submits too.
    e.stopPropagation();
    const required: Record<string, string[]> = {};
    if (!form.address_line_one.trim()) required.address_line_one = ["Enter the address"];
    if (!form.city.trim()) required.city = ["Enter the city"];
    if (!form.state.trim()) required.state = ["Enter the state"];
    if (!form.phone.trim()) required.phone = ["Enter a mobile number"];
    if (!form.pincode.trim()) required.pincode = ["Enter the pincode"];
    const pre = { ...required, ...identityErrors(form) };
    if (Object.keys(pre).length > 0) {
      setErrors(pre);
      return;
    }

    setSaving(true);
    try {
      const res = await customerApi.createAddress(token, { ...form, phone: normalizeMobile(form.phone), gst: form.gst || null });
      onSaved(res.data);
    } catch (err) {
      if (err instanceof ApiException && err.errors) setErrors(err.errors);
      else setErrors({ address_line_one: [err instanceof Error ? err.message : "Could not save the address"] });
    } finally {
      setSaving(false);
    }
  }

  const input = (key: keyof Form, label: string, props: React.InputHTMLAttributes<HTMLInputElement> = {}) => (
    <div>
      <label htmlFor={`addr-${key}`} className="mb-1 block text-xs font-medium text-gray-700">{label}</label>
      <input
        id={`addr-${key}`}
        value={form[key]}
        onChange={(e) => set(key, e.target.value)}
        aria-invalid={!!errors[key]?.length}
        className="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm focus:border-[#CC1414] focus:outline-none"
        {...props}
      />
      <FieldError message={errors[key]?.[0]} />
    </div>
  );

  // A portal: callers render this inside their own <form>, and a nested form
  // is invalid HTML — the browser drops it and "Save" submits the outer form.
  if (typeof document === "undefined") return null;
  return createPortal(
    <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4" role="dialog" aria-modal aria-label="Add new address">
      <form onSubmit={submit} noValidate className="relative max-h-[90dvh] w-full max-w-lg overflow-y-auto rounded-2xl bg-white p-6 shadow-xl">
        <button type="button" onClick={onClose} aria-label="Close" className="absolute right-4 top-4 rounded-lg p-1 text-gray-400 hover:bg-gray-100">
          <X size={16} />
        </button>
        <h2 className="mb-4 text-lg font-bold text-gray-900">Add new address</h2>
        <div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
          {input("company_name", "Company name")}
          {input("gst", "GSTIN (optional)", { maxLength: 15, onChange: (e) => set("gst", e.target.value.toUpperCase().replace(/[^0-9A-Z]/g, "")) })}
          <div className="sm:col-span-2">{input("address_line_one", "Address line 1 *")}</div>
          <div className="sm:col-span-2">{input("address_line_two", "Address line 2")}</div>
          {input("pincode", "Pincode *", { inputMode: "numeric", maxLength: 6, onChange: (e) => set("pincode", e.target.value.replace(/\D/g, "").slice(0, 6)) })}
          {input("phone", "Mobile *", { inputMode: "numeric", maxLength: 10, onChange: (e) => set("phone", e.target.value.replace(/\D/g, "").slice(0, 10)) })}
          {input("city", "City *")}
          {input("state", "State *")}
        </div>
        {lookup.loading && <p className="mt-2 text-xs text-gray-500">Looking up pincode…</p>}
        <div className="mt-5 flex justify-end gap-2">
          <button type="button" onClick={onClose} className="rounded-lg border border-gray-200 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">
            Cancel
          </button>
          <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…" : "Save address"}
          </button>
        </div>
      </form>
    </div>,
    document.body
  );
}
