"use client";

import { LoaderCircle, MapPin, PencilLine, Plus, Star, Trash2 } from "lucide-react";
import { useEffect, useMemo, useState } from "react";
import {
  applyPreferredAddressToClient,
  formatPhone,
  formatZipCode,
  getAddressRecipient,
  getAddressSummary,
  normalizeClientAddressInput,
  type ClientAddress,
} from "@/lib/client-portal-addresses";
import type { ClientPortalClient } from "@/components/client-portal/shared";
import { getReadableTextColor } from "@/lib/color-contrast";

const inputClass =
  "w-full rounded-xl border border-zinc-200/80 bg-white px-3.5 py-3 text-sm text-zinc-900 outline-none transition placeholder:text-zinc-400 focus:border-zinc-300 focus:ring-4 focus:ring-zinc-100";

type AddressFormState = {
  label: string;
  recipient_name: string;
  phone: string;
  zip: string;
  street: string;
  number: string;
  complement: string;
  neighborhood: string;
  city: string;
  state: string;
  reference: string;
  is_default: boolean;
};

function buildEmptyForm(isDefault = false): AddressFormState {
  return {
    label: "",
    recipient_name: "",
    phone: "",
    zip: "",
    street: "",
    number: "",
    complement: "",
    neighborhood: "",
    city: "",
    state: "",
    reference: "",
    is_default: isDefault,
  };
}

function toForm(address: ClientAddress | null | undefined): AddressFormState {
  return {
    label: String(address?.label || ""),
    recipient_name: String(address?.recipient_name || ""),
    phone: formatPhone(address?.phone || ""),
    zip: formatZipCode(address?.zip || ""),
    street: String(address?.street || ""),
    number: String(address?.number || ""),
    complement: String(address?.complement || ""),
    neighborhood: String(address?.neighborhood || ""),
    city: String(address?.city || ""),
    state: String(address?.state || ""),
    reference: String(address?.reference || ""),
    is_default: Boolean(address?.is_default),
  };
}

export default function ClientAddressBook({
  slug,
  client,
  primaryColor,
  onClientChange,
}: {
  slug: string;
  client: ClientPortalClient;
  primaryColor: string;
  onClientChange?: (client: ClientPortalClient) => void;
}) {
  const [addresses, setAddresses] = useState<ClientAddress[]>(() =>
    Array.isArray(client.addresses) ? client.addresses : []
  );
  const [editingId, setEditingId] = useState<string | "new" | null>(null);
  const [form, setForm] = useState<AddressFormState>(() => buildEmptyForm(addresses.length === 0));
  const [saving, setSaving] = useState(false);
  /* Confirmacao dentro do proprio cartao: alerta do navegador aqui mostra o
     endereco do site e nao explica o que sera removido. */
  const [confirmingDelete, setConfirmingDelete] = useState<string | null>(null);
  const [zipLoading, setZipLoading] = useState(false);
  const [status, setStatus] = useState<{ type: "success" | "error"; text: string } | null>(null);

  useEffect(() => {
    setAddresses(Array.isArray(client.addresses) ? client.addresses : []);
  }, [client.addresses]);

  const sortedAddresses = useMemo(
    () =>
      [...addresses].sort((a, b) => {
        if (Boolean(a.is_default) !== Boolean(b.is_default)) return a.is_default ? -1 : 1;
        return new Date(b.updated_at || b.created_at || 0).getTime() - new Date(a.updated_at || a.created_at || 0).getTime();
      }),
    [addresses]
  );

  function emitClientChange(nextAddresses: ClientAddress[]) {
    const nextClient = applyPreferredAddressToClient(client, nextAddresses) as ClientPortalClient;
    setAddresses(nextAddresses);
    onClientChange?.(nextClient);
  }

  function updateField<K extends keyof AddressFormState>(key: K, value: AddressFormState[K]) {
    setForm((prev) => ({ ...prev, [key]: value }));
  }

  function resetForm(nextDefault = false) {
    setEditingId(null);
    setForm(buildEmptyForm(nextDefault));
  }

  function startCreate() {
    setStatus(null);
    setEditingId("new");
    setForm(buildEmptyForm(addresses.length === 0));
  }

  function startEdit(address: ClientAddress) {
    setStatus(null);
    setEditingId(address.id);
    setForm(toForm(address));
  }

  async function handleZipLookup(rawZip: string) {
    const zip = String(rawZip || "").replace(/\D/g, "");
    if (zip.length !== 8 || zipLoading) return;

    setZipLoading(true);
    try {
      const response = await fetch(`https://viacep.com.br/ws/${zip}/json/`);
      const data = (await response.json()) as {
        erro?: boolean;
        logradouro?: string;
        bairro?: string;
        localidade?: string;
        uf?: string;
      };

      if (!response.ok || data.erro) {
        throw new Error("CEP nao encontrado.");
      }

      setForm((prev) => ({
        ...prev,
        zip: formatZipCode(zip),
        street: data.logradouro || prev.street,
        neighborhood: data.bairro || prev.neighborhood,
        city: data.localidade || prev.city,
        state: data.uf || prev.state,
      }));
    } catch {
      setStatus({ type: "error", text: "Nao foi possivel buscar o CEP agora." });
    } finally {
      setZipLoading(false);
    }
  }

  async function handleSave() {
    if (saving) return;
    setSaving(true);
    setStatus(null);
    try {
      const payload = normalizeClientAddressInput(form);
      const url = "/api/client-portal/addresses";
      const response = await fetch(url, {
        method: editingId && editingId !== "new" ? "PATCH" : "POST",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({
          slug,
          id: editingId && editingId !== "new" ? editingId : undefined,
          ...payload,
        }),
      });
      const data = (await response.json()) as { error?: string; address?: ClientAddress };
      if (!response.ok || data.error || !data.address?.id) {
        throw new Error(data.error || "Nao foi possivel salvar o endereco.");
      }

      const nextAddressesBase =
        editingId && editingId !== "new"
          ? addresses.map((address) => (address.id === data.address?.id ? data.address : address))
          : [data.address, ...addresses];
      const nextAddresses = data.address.is_default
        ? nextAddressesBase.map((address) => ({
            ...address,
            is_default: address.id === data.address?.id,
          }))
        : nextAddressesBase;

      emitClientChange(nextAddresses);
      setStatus({ type: "success", text: editingId === "new" ? "Endereco cadastrado." : "Endereco atualizado." });
      resetForm(false);
    } catch (error) {
      const message =
        typeof error === "object" && error && "message" in error && typeof error.message === "string"
          ? error.message
          : "Nao foi possivel salvar o endereco.";
      setStatus({ type: "error", text: message });
    } finally {
      setSaving(false);
    }
  }

  async function handleDelete(address: ClientAddress) {
    if (saving) return;
    setConfirmingDelete(null);

    setSaving(true);
    setStatus(null);
    try {
      const response = await fetch(
        `/api/client-portal/addresses?slug=${encodeURIComponent(slug)}&id=${encodeURIComponent(address.id)}`,
        { method: "DELETE" }
      );
      const data = (await response.json()) as { error?: string };
      if (!response.ok || data.error) {
        throw new Error(data.error || "Nao foi possivel remover o endereco.");
      }

      const remaining = addresses.filter((item) => item.id !== address.id);
      let nextAddresses = remaining;
      if (address.is_default && remaining.length > 0) {
        nextAddresses = remaining.map((item, index) => ({
          ...item,
          is_default: index === 0,
        }));
      }
      emitClientChange(nextAddresses);
      if (editingId === address.id) {
        resetForm(nextAddresses.length === 0);
      }
      setStatus({ type: "success", text: "Endereco removido." });
    } catch (error) {
      const message =
        typeof error === "object" && error && "message" in error && typeof error.message === "string"
          ? error.message
          : "Nao foi possivel remover o endereco.";
      setStatus({ type: "error", text: message });
    } finally {
      setSaving(false);
    }
  }

  async function handleSetDefault(address: ClientAddress) {
    if (saving || address.is_default) return;
    setSaving(true);
    setStatus(null);
    try {
      const response = await fetch("/api/client-portal/addresses", {
        method: "PATCH",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({
          slug,
          id: address.id,
          label: address.label,
          recipient_name: address.recipient_name,
          phone: address.phone,
          zip: address.zip,
          street: address.street,
          number: address.number,
          complement: address.complement,
          neighborhood: address.neighborhood,
          city: address.city,
          state: address.state,
          reference: address.reference,
          is_default: true,
        }),
      });
      const data = (await response.json()) as { error?: string; address?: ClientAddress };
      if (!response.ok || data.error || !data.address?.id) {
        throw new Error(data.error || "Nao foi possivel definir o endereco principal.");
      }

      const nextAddresses = addresses.map((item) => ({
        ...item,
        ...(item.id === data.address?.id ? data.address : null),
        is_default: item.id === data.address?.id,
      }));
      emitClientChange(nextAddresses);
      setStatus({ type: "success", text: "Endereco principal atualizado." });
    } catch (error) {
      const message =
        typeof error === "object" && error && "message" in error && typeof error.message === "string"
          ? error.message
          : "Nao foi possivel definir o endereco principal.";
      setStatus({ type: "error", text: message });
    } finally {
      setSaving(false);
    }
  }

  return (
    <div className="space-y-5">
      <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
        <div>
          <div className="text-[15px] font-semibold text-zinc-950">Meus enderecos</div>
          <div className="mt-1 text-[13px] text-zinc-500">
            Cadastre varios enderecos e defina qual fica como principal.
          </div>
        </div>
        <button
          type="button"
          onClick={startCreate}
          className="inline-flex h-11 items-center justify-center gap-2 border border-zinc-200 px-4 text-sm font-semibold text-zinc-700 transition hover:bg-zinc-50 hover:text-zinc-950"
          style={primaryColor ? { color: primaryColor } : undefined}
        >
          <Plus className="h-4 w-4" />
          Novo endereco
        </button>
      </div>

      {status ? (
        <div
          className={`rounded-2xl border px-4 py-3 text-sm ${
            status.type === "success" ? "border-emerald-200 bg-emerald-50 text-emerald-700" : "border-rose-200 bg-rose-50 text-rose-700"
          }`}
        >
          {status.text}
        </div>
      ) : null}

      {sortedAddresses.length > 0 ? (
        <div className="grid gap-4 lg:grid-cols-2">
          {sortedAddresses.map((address) => (
            <div key={address.id} className="rounded-[24px] border border-zinc-200/80 bg-white p-5">
              <div className="flex items-start justify-between gap-3">
                <div className="min-w-0">
                  <div className="flex flex-wrap items-center gap-2">
                    <div className="text-[16px] font-semibold text-zinc-950">
                      {address.label || "Endereco"}
                    </div>
                    {address.is_default ? (
                      <span className="inline-flex items-center gap-1 rounded-full border border-emerald-200 bg-emerald-50 px-2.5 py-1 text-[11px] font-semibold text-emerald-700">
                        <Star className="h-3.5 w-3.5" />
                        Principal
                      </span>
                    ) : null}
                  </div>
                  <div className="mt-2 text-sm font-medium text-zinc-800">
                    {getAddressRecipient(address, client.company_name || client.name)}
                  </div>
                </div>
                <div className="flex items-center gap-1">
                  <button
                    type="button"
                    onClick={() => startEdit(address)}
                    className="inline-flex h-9 w-9 items-center justify-center rounded-full border border-zinc-200 text-zinc-600 transition hover:bg-zinc-50 hover:text-zinc-950"
                  >
                    <PencilLine className="h-4 w-4" />
                  </button>
                  <button
                    type="button"
                    onClick={() => setConfirmingDelete(address.id)}
                    disabled={saving}
                    className="inline-flex h-9 w-9 items-center justify-center rounded-full border border-zinc-200 text-zinc-600 transition hover:bg-zinc-50 hover:text-rose-600 disabled:opacity-60"
                  >
                    <Trash2 className="h-4 w-4" />
                  </button>
                </div>
              </div>

              {confirmingDelete === address.id ? (
                <div className="mt-4 flex flex-wrap items-center gap-3 rounded-2xl border border-rose-100 bg-rose-50 px-4 py-3 text-sm text-rose-700">
                  <span className="flex-1">Remover este endereço da sua conta?</span>
                  <button
                    type="button"
                    onClick={() => setConfirmingDelete(null)}
                    className="h-9 rounded-xl bg-white px-3 text-[13px] font-semibold text-zinc-600"
                  >
                    Cancelar
                  </button>
                  <button
                    type="button"
                    disabled={saving}
                    onClick={() => void handleDelete(address)}
                    className="h-9 rounded-xl bg-rose-600 px-3 text-[13px] font-semibold text-white disabled:opacity-60"
                  >
                    Remover
                  </button>
                </div>
              ) : null}

              <div className="mt-4 rounded-2xl border border-zinc-100 bg-zinc-50 px-4 py-3 text-sm text-zinc-700">
                {getAddressSummary(address)}
              </div>

              <div className="mt-4 flex flex-wrap items-center gap-3 text-[13px] text-zinc-500">
                {address.phone ? <span>Contato: {formatPhone(address.phone)}</span> : null}
                {address.reference ? <span>Referencia: {address.reference}</span> : null}
              </div>

              {!address.is_default ? (
                <div className="mt-4 border-t border-zinc-100 pt-4">
                  <button
                    type="button"
                    onClick={() => void handleSetDefault(address)}
                    disabled={saving}
                    className="inline-flex h-10 items-center border border-zinc-200 px-4 text-sm font-semibold text-zinc-700 transition hover:bg-zinc-50 hover:text-zinc-950 disabled:opacity-60"
                  >
                    Definir como principal
                  </button>
                </div>
              ) : null}
            </div>
          ))}
        </div>
      ) : (
        <div className="rounded-[24px] border border-dashed border-zinc-300 bg-zinc-50 px-6 py-10 text-center">
          <MapPin className="mx-auto h-10 w-10 text-zinc-300" />
          <div className="mt-4 text-[18px] font-semibold text-zinc-950">Nenhum endereco cadastrado</div>
          <div className="mt-2 text-sm leading-6 text-zinc-500">
            Cadastre enderecos de entrega para escolher rapidamente onde quer receber em cada compra.
          </div>
        </div>
      )}

      {editingId ? (
        <div className="rounded-[24px] border border-zinc-200/80 bg-zinc-50/70 p-4 sm:p-5">
          <div className="mb-4 flex items-center justify-between gap-3">
            <div>
              <div className="text-[15px] font-semibold text-zinc-950">
                {editingId === "new" ? "Novo endereco" : "Editar endereco"}
              </div>
              <div className="mt-1 text-[13px] text-zinc-500">
                Preencha os dados de entrega e, se quiser, marque como principal.
              </div>
            </div>
            <button
              type="button"
              onClick={() => resetForm(addresses.length === 0)}
              className="text-sm font-semibold text-zinc-500 transition hover:text-zinc-900"
            >
              Cancelar
            </button>
          </div>

          <div className="grid grid-cols-1 gap-3 md:grid-cols-2">
            <label className="space-y-2">
              <span className="text-sm font-medium text-zinc-700">Apelido</span>
              <input
                value={form.label}
                onChange={(event) => updateField("label", event.target.value)}
                placeholder="Casa, Trabalho, Loja..."
                className={inputClass}
              />
            </label>
            <label className="space-y-2">
              <span className="text-sm font-medium text-zinc-700">Destinatario</span>
              <input
                value={form.recipient_name}
                onChange={(event) => updateField("recipient_name", event.target.value)}
                placeholder="Quem vai receber"
                className={inputClass}
              />
            </label>
            <label className="space-y-2">
              <span className="text-sm font-medium text-zinc-700">Telefone</span>
              <input
                value={form.phone}
                onChange={(event) => updateField("phone", formatPhone(event.target.value))}
                placeholder="(00) 00000-0000"
                className={inputClass}
                inputMode="tel"
              />
            </label>
            <label className="space-y-2">
              <span className="text-sm font-medium text-zinc-700">CEP</span>
              <div className="flex gap-2">
                <input
                  value={form.zip}
                  onChange={(event) => updateField("zip", formatZipCode(event.target.value))}
                  onBlur={() => void handleZipLookup(form.zip)}
                  placeholder="00000-000"
                  className={inputClass}
                  inputMode="numeric"
                />
                <button
                  type="button"
                  onClick={() => void handleZipLookup(form.zip)}
                  disabled={zipLoading}
                  className="inline-flex min-w-[88px] items-center justify-center rounded-xl border border-zinc-200 bg-white px-4 text-sm font-semibold text-zinc-700 transition hover:bg-zinc-50 disabled:opacity-60"
                >
                  {zipLoading ? <LoaderCircle className="h-4 w-4 animate-spin" /> : "Buscar"}
                </button>
              </div>
            </label>
            <label className="space-y-2 md:col-span-2">
              <span className="text-sm font-medium text-zinc-700">Rua</span>
              <input
                value={form.street}
                onChange={(event) => updateField("street", event.target.value)}
                placeholder="Nome da rua"
                className={inputClass}
              />
            </label>
            <label className="space-y-2">
              <span className="text-sm font-medium text-zinc-700">Numero</span>
              <input
                value={form.number}
                onChange={(event) => updateField("number", event.target.value)}
                placeholder="123"
                className={inputClass}
              />
            </label>
            <label className="space-y-2">
              <span className="text-sm font-medium text-zinc-700">Complemento</span>
              <input
                value={form.complement}
                onChange={(event) => updateField("complement", event.target.value)}
                placeholder="Opcional"
                className={inputClass}
              />
            </label>
            <label className="space-y-2">
              <span className="text-sm font-medium text-zinc-700">Bairro</span>
              <input
                value={form.neighborhood}
                onChange={(event) => updateField("neighborhood", event.target.value)}
                placeholder="Seu bairro"
                className={inputClass}
              />
            </label>
            <div className="grid grid-cols-[minmax(0,1fr)_96px] gap-3">
              <label className="space-y-2">
                <span className="text-sm font-medium text-zinc-700">Cidade</span>
                <input
                  value={form.city}
                  onChange={(event) => updateField("city", event.target.value)}
                  placeholder="Sua cidade"
                  className={inputClass}
                />
              </label>
              <label className="space-y-2">
                <span className="text-sm font-medium text-zinc-700">UF</span>
                <input
                  value={form.state}
                  onChange={(event) => updateField("state", event.target.value.toUpperCase())}
                  placeholder="UF"
                  maxLength={2}
                  className={inputClass}
                />
              </label>
            </div>
            <label className="space-y-2 md:col-span-2">
              <span className="text-sm font-medium text-zinc-700">Referencia</span>
              <input
                value={form.reference}
                onChange={(event) => updateField("reference", event.target.value)}
                placeholder="Ponto de referencia opcional"
                className={inputClass}
              />
            </label>
          </div>

          <label className="mt-4 inline-flex items-center gap-2 text-sm text-zinc-700">
            <input
              type="checkbox"
              checked={form.is_default}
              onChange={(event) => updateField("is_default", event.target.checked)}
              className="h-4 w-4 rounded border-zinc-300"
            />
            Definir como endereco principal
          </label>

          <div className="mt-5 flex flex-wrap gap-3">
            <button
              type="button"
              onClick={() => void handleSave()}
              disabled={saving}
              className="inline-flex h-11 items-center justify-center gap-2 px-5 text-sm font-semibold text-white transition hover:opacity-90 disabled:opacity-60"
              style={{ backgroundColor: primaryColor, color: getReadableTextColor(primaryColor) }}
            >
              {saving ? <LoaderCircle className="h-4 w-4 animate-spin" /> : null}
              {editingId === "new" ? "Salvar endereco" : "Atualizar endereco"}
            </button>
            <button
              type="button"
              onClick={() => resetForm(addresses.length === 0)}
              className="inline-flex h-11 items-center justify-center border border-zinc-200 px-5 text-sm font-semibold text-zinc-700 transition hover:bg-zinc-50 hover:text-zinc-950"
            >
              Cancelar
            </button>
          </div>
        </div>
      ) : null}
    </div>
  );
}
