"use client";

import { FormEvent, useEffect, useMemo, useState } from "react";

import { useLocale } from "@/components/providers/locale-provider";
import { PaginationFooter } from "@/components/shared/pagination-footer";
import { useCurrentUser } from "@/hooks/use-current-user";
import { usePagination } from "@/hooks/use-pagination";
import type { ApiErrorResponse, DetailResponse } from "@/types/api";
import type {
  BankRecord,
  CurrencyRecord,
  MasterStatus,
  WarehouseRecord
} from "@/types/master-data";

type RecordMap = {
  bank: BankRecord;
  currency: CurrencyRecord;
  warehouse: WarehouseRecord;
};

type Kind = keyof RecordMap;

type SimpleMasterCrudProps<K extends Kind> = {
  kind: K;
  endpoint: string;
  title: string;
  helper: string;
};

type BaseForm = {
  code: string;
  name: string;
  status: MasterStatus;
  description?: string;
  address?: string;
};

const currencyRegionMap: Record<string, string> = {
  IDR: "ASEAN",
  SGD: "ASEAN",
  MYR: "ASEAN",
  THB: "ASEAN",
  PHP: "ASEAN",
  VND: "ASEAN",
  KHR: "ASEAN",
  LAK: "ASEAN",
  MMK: "ASEAN",
  USD: "Americas",
  CAD: "Americas",
  MXN: "Americas",
  BRL: "Americas",
  ARS: "Americas",
  CLP: "Americas",
  COP: "Americas",
  PEN: "Americas",
  EUR: "Europe",
  GBP: "Europe",
  CHF: "Europe",
  SEK: "Europe",
  NOK: "Europe",
  DKK: "Europe",
  PLN: "Europe",
  CZK: "Europe",
  HUF: "Europe",
  TRY: "Europe",
  JPY: "Asia",
  CNY: "Asia",
  HKD: "Asia",
  KRW: "Asia",
  TWD: "Asia",
  INR: "Asia",
  PKR: "Asia",
  BDT: "Asia",
  AED: "Middle East",
  SAR: "Middle East",
  QAR: "Middle East",
  KWD: "Middle East",
  BHD: "Middle East",
  OMR: "Middle East",
  ILS: "Middle East",
  AUD: "Oceania",
  NZD: "Oceania",
  ZAR: "Africa",
  NGN: "Africa",
  EGP: "Africa",
  KES: "Africa"
};

const currencyRegionOrder = [
  "ASEAN",
  "Asia",
  "Middle East",
  "Europe",
  "Americas",
  "Africa",
  "Oceania",
  "Others"
] as const;

function getCurrencyRegion(code: string) {
  return currencyRegionMap[code.toUpperCase()] ?? "Others";
}

export function SimpleMasterCrud<K extends Kind>({
  kind,
  endpoint,
  title,
  helper
}: SimpleMasterCrudProps<K>) {
  const { dict, locale } = useLocale();
  const [items, setItems] = useState<RecordMap[K][]>([]);
  const [search, setSearch] = useState("");
  const [statusFilter, setStatusFilter] = useState<MasterStatus | "ALL">("ALL");
  const [regionFilter, setRegionFilter] = useState<string>("ALL");
  const [form, setForm] = useState<BaseForm>(() => getEmptyForm(kind));
  const [editingId, setEditingId] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);
  const [submitting, setSubmitting] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const { canEditCode } = useCurrentUser();
  const filteredItems = useMemo(() => {
    const keyword = search.trim().toLowerCase();
    const nextItems = items.filter((item) => {
      const matchesStatus = statusFilter === "ALL" || item.status === statusFilter;
      if (!matchesStatus) return false;

      if (kind === "currency" && regionFilter !== "ALL") {
        const typed = item as CurrencyRecord;
        if (getCurrencyRegion(typed.code) !== regionFilter) return false;
      }

      const searchable = [
        item.code,
        item.name,
        "address" in item ? item.address ?? "" : "",
        "description" in item ? item.description ?? "" : "",
        kind === "currency" ? getCurrencyRegion((item as CurrencyRecord).code) : ""
      ];
      return keyword.length === 0 || searchable.some((value) => value.toLowerCase().includes(keyword));
    });

    if (kind !== "currency") return nextItems;

    return [...nextItems].sort((left, right) => {
      const leftCurrency = left as CurrencyRecord;
      const rightCurrency = right as CurrencyRecord;
      const leftRegionIndex = currencyRegionOrder.indexOf(
        getCurrencyRegion(leftCurrency.code) as (typeof currencyRegionOrder)[number]
      );
      const rightRegionIndex = currencyRegionOrder.indexOf(
        getCurrencyRegion(rightCurrency.code) as (typeof currencyRegionOrder)[number]
      );

      if (leftRegionIndex !== rightRegionIndex) return leftRegionIndex - rightRegionIndex;
      return leftCurrency.code.localeCompare(rightCurrency.code);
    });
  }, [items, kind, regionFilter, search, statusFilter]);

  const currencyRegionOptions = useMemo(() => {
    if (kind !== "currency") return [];
    const regions = new Set(
      items.map((item) => getCurrencyRegion((item as CurrencyRecord).code))
    );
    return currencyRegionOrder.filter((region) => regions.has(region));
  }, [items, kind]);
  const pagination = usePagination(filteredItems, 20);

  async function loadItems() {
    setLoading(true);
    setError(null);
    try {
      const response = await fetch(endpoint, { cache: "no-store" });
      const payload = (await response.json()) as { data: RecordMap[K][] };
      if (!response.ok) throw new Error(dict.master.loadError);
      setItems(payload.data);
    } catch (err) {
      setError(err instanceof Error ? err.message : dict.master.loadError);
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    void loadItems();
  }, [endpoint]);

  function resetForm() {
    setEditingId(null);
    setForm(getEmptyForm(kind));
    setError(null);
  }

  function startEdit(item: RecordMap[K]) {
    setEditingId(item.id);
    setError(null);
    if (kind === "currency") {
      const typed = item as CurrencyRecord;
      setForm({ code: typed.code, name: typed.name, description: typed.description ?? "", status: typed.status as MasterStatus });
      return;
    }
    if (kind === "bank") {
      const typed = item as BankRecord;
      setForm({ code: typed.code, name: typed.name, address: typed.address ?? "", status: typed.status as MasterStatus });
      return;
    }
    const typed = item as WarehouseRecord;
    setForm({ code: typed.code, name: typed.name, address: typed.address ?? "", status: typed.status as MasterStatus });
  }

  async function handleSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    setSubmitting(true);
    setError(null);
    const payload = buildPayload(kind, form);
    try {
      const response = await fetch(editingId ? `${endpoint}/${editingId}` : endpoint, {
        method: editingId ? "PUT" : "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(payload)
      });
      const result = (await response.json()) as DetailResponse<RecordMap[K]> | ApiErrorResponse;
      if (!response.ok) {
        if ("errors" in result && result.errors) {
          const firstError = Object.values(result.errors)[0]?.[0];
          throw new Error(firstError ?? result.message ?? dict.common.requestFailed);
        }
        throw new Error("message" in result ? result.message : dict.common.requestFailed);
      }
      resetForm();
      await loadItems();
    } catch (err) {
      setError(err instanceof Error ? err.message : dict.master.saveError);
    } finally {
      setSubmitting(false);
    }
  }

  async function handleDelete(id: string) {
    if (!window.confirm(`${dict.master.confirmDeletePrefix} ${title.toLowerCase()} ini?`)) return;
    try {
      const response = await fetch(`${endpoint}/${id}`, { method: "DELETE" });
      if (!response.ok) {
        const payload = (await response.json()) as ApiErrorResponse;
        throw new Error(payload.message);
      }
      if (editingId === id) resetForm();
      await loadItems();
    } catch (err) {
      setError(err instanceof Error ? err.message : dict.master.deleteError);
    }
  }

  return (
    <section className="grid gap-6 xl:grid-cols-[0.92fr_1.08fr]">
      <div className="ops-card p-6">
        <div className="flex items-start justify-between gap-4">
          <div>
            <p className="ops-overline">{dict.master.overline}</p>
            <h2 className="mt-2 text-[28px] font-semibold tracking-tight text-ink">{editingId ? `${dict.common.edit} ${title}` : `${dict.master.add} ${title}`}</h2>
            <p className="mt-3 text-[13px] leading-6 text-slate-500">{helper}</p>
          </div>
          {editingId ? <button type="button" onClick={resetForm} className="ops-btn-secondary">{dict.common.cancelEdit}</button> : null}
        </div>
        <form className="mt-6 space-y-4" onSubmit={handleSubmit}>
          <div className="grid gap-4 md:grid-cols-2">
            <Field
              label={dict.master.code}
              value={form.code}
              onChange={(v) => setForm((c) => ({ ...c, code: v }))}
              readOnly={kind === "currency" || kind === "bank" ? false : !canEditCode}
              placeholder={kind === "currency" ? "IDR" : kind === "bank" ? "014" : canEditCode ? undefined : "Auto"}
            />
            <Field label={dict.master.name} value={form.name} onChange={(v) => setForm((c) => ({ ...c, name: v }))} />
          </div>
          {kind !== "warehouse" && kind !== "bank" ? (
            <label className="block">
              <span className="ops-label">{dict.master.description}</span>
              <textarea value={form.description ?? ""} onChange={(e) => setForm((c) => ({ ...c, description: e.target.value }))} rows={4} className="ops-textarea" />
            </label>
          ) : (
            <label className="block">
              <span className="ops-label">{dict.master.address}</span>
              <textarea value={form.address ?? ""} onChange={(e) => setForm((c) => ({ ...c, address: e.target.value }))} rows={4} className="ops-textarea" />
            </label>
          )}
          <label className="block">
            <span className="ops-label">{dict.master.status}</span>
            <select value={form.status} onChange={(e) => setForm((c) => ({ ...c, status: e.target.value as MasterStatus }))} className="ops-select">
              <option value="ACTIVE">{dict.master.active}</option>
              <option value="INACTIVE">{dict.master.inactive}</option>
            </select>
          </label>
          {error ? <div className="rounded border border-ember/30 bg-ember/10 px-4 py-3 text-sm text-ember">{error}</div> : null}
          <button type="submit" disabled={submitting} className="ops-btn-primary">
            {submitting ? dict.common.processing : editingId ? `${dict.master.update} ${title.toLowerCase()}` : `${dict.master.add} ${title.toLowerCase()}`}
          </button>
        </form>
      </div>
      <div className="ops-table-shell">
        <div className="ops-section-head">
          <div>
            <p className="ops-title">{dict.master.list} {title}</p>
          </div>
          <div className="ops-chip-muted">{items.length} {dict.master.dataCount}</div>
        </div>
        {!loading && items.length > 0 ? (
          <div className="border-t border-line/70 px-6 py-4">
            <div className={`grid gap-4 ${kind === "currency" ? "md:grid-cols-[1fr_180px_220px]" : "md:grid-cols-[1fr_180px]"}`}>
              <label className="block">
                <span className="ops-label">Cari data</span>
                <input
                  value={search}
                  onChange={(event) => setSearch(event.target.value)}
                  placeholder={`Cari ${title.toLowerCase()}...`}
                  className="ops-input"
                />
              </label>
              <label className="block">
                <span className="ops-label">{dict.master.status}</span>
                <select
                  value={statusFilter}
                  onChange={(event) => setStatusFilter(event.target.value as MasterStatus | "ALL")}
                  className="ops-select"
                >
                  <option value="ALL">
                    {locale === "id" ? "Semua status" : "All statuses"}
                  </option>
                  <option value="ACTIVE">{dict.master.active}</option>
                  <option value="INACTIVE">{dict.master.inactive}</option>
                </select>
              </label>
              {kind === "currency" ? (
                <label className="block">
                  <span className="ops-label">Kawasan</span>
                  <select
                    value={regionFilter}
                    onChange={(event) => setRegionFilter(event.target.value)}
                    className="ops-select"
                  >
                    <option value="ALL">
                      {locale === "id" ? "Semua kawasan" : "All regions"}
                    </option>
                    {currencyRegionOptions.map((region) => (
                      <option key={region} value={region}>
                        {region}
                      </option>
                    ))}
                  </select>
                </label>
              ) : null}
            </div>
          </div>
        ) : null}
        {loading ? <div className="px-6 py-8 text-sm text-slate-500">{dict.common.loading}</div> : items.length === 0 ? <div className="px-6 py-8 text-sm text-slate-500">{dict.master.noData}</div> : filteredItems.length === 0 ? <div className="px-6 py-8 text-sm text-slate-500">Tidak ada data yang cocok dengan pencarian.</div> : (
          <div className="overflow-x-auto">
            <table className="ops-table">
              <thead>
                <tr>
                  <th>{dict.master.code}</th>
                  <th>{dict.master.name}</th>
                  {kind === "currency" ? <th>Kawasan</th> : null}
                  <th>{kind === "warehouse" || kind === "bank" ? dict.master.address : dict.master.description}</th>
                  <th>{dict.master.status}</th>
                  <th>{dict.common.actions}</th>
                </tr>
              </thead>
              <tbody>
                {pagination.pagedItems.map((item) => (
                  <tr key={item.id}>
                    <td className="font-semibold text-ink">{item.code}</td>
                    <td>{item.name}</td>
                    {kind === "currency" ? (
                      <td>
                        <span className="ops-chip-muted">
                          {getCurrencyRegion((item as CurrencyRecord).code)}
                        </span>
                      </td>
                    ) : null}
                    <td className="text-slate-600">
                      {"address" in item ? (
                        item.address || "-"
                      ) : (
                        item.description || "-"
                      )}
                    </td>
                    <td>
                      <span className={item.status === "INACTIVE" ? "ops-chip-danger" : "ops-chip-active"}>{item.status === "INACTIVE" ? dict.master.inactive : dict.master.active}</span>
                    </td>
                    <td>
                      <div className="flex gap-2">
                        <button type="button" onClick={() => startEdit(item)} className="ops-btn-secondary">{dict.common.edit}</button>
                        <button type="button" onClick={() => void handleDelete(item.id)} className="ops-btn-danger">{dict.common.delete}</button>
                      </div>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        )}
        {!loading && items.length > 0 ? (
          <PaginationFooter
            page={pagination.page}
            totalPages={pagination.totalPages}
            rangeStart={pagination.rangeStart}
            rangeEnd={pagination.rangeEnd}
            totalItems={pagination.totalItems}
            itemLabel={title.toLowerCase()}
            onPrev={() => pagination.setPage((current) => Math.max(1, current - 1))}
            onNext={() => pagination.setPage((current) => Math.min(pagination.totalPages, current + 1))}
          />
        ) : null}
      </div>
    </section>
  );
}

function getEmptyForm(kind: Kind): BaseForm {
  if (kind === "warehouse" || kind === "bank") return { code: "", name: "", address: "", status: "ACTIVE" };
  return { code: "", name: "", description: "", status: "ACTIVE" };
}

function buildPayload(kind: Kind, form: BaseForm) {
  if (kind === "warehouse" || kind === "bank") {
    return {
      code: form.code,
      name: form.name,
      address: form.address ?? "",
      status: form.status
    };
  }
  return {
    code: form.code,
    name: form.name,
    description: form.description ?? "",
    status: form.status
  };
}

function Field({
  label,
  value,
  onChange,
  readOnly = false,
  placeholder
}: {
  label: string;
  value: string;
  onChange: (value: string) => void;
  readOnly?: boolean;
  placeholder?: string;
}) {
  return (
    <label className="block">
      <span className="ops-label">{label}</span>
      <input
        value={value}
        readOnly={readOnly}
        placeholder={placeholder}
        onChange={(event) => onChange(event.target.value)}
        className="ops-input"
      />
    </label>
  );
}
