"use client";

import type { HTMLAttributes } from "react";
import Link from "next/link";
import { useSearchParams } from "next/navigation";
import { useEffect, useMemo, useState } from "react";

import { useLocale } from "@/components/providers/locale-provider";
import { SearchableSelectField } from "@/components/shared/searchable-select-field";
import { formatCurrencyAmount } from "@/lib/formatters";
import type { ApiErrorResponse, DetailResponse } from "@/types/api";
import type { LotListItem } from "@/types/lot";
import type {
  GradeRecord,
  WarehouseLocationRecord,
  WarehouseRecord,
  WashingPlaceRecord
} from "@/types/master-data";
import type { WashingListItem } from "@/types/washing";

type WashingForm = {
  lot_id: string;
  washing_place_id: string;
  washing_cost: string;
  duration_hours: string;
  receipt_file: File | null;
};

type CompleteForm = {
  after_qty: string;
  grade_id: string;
  warehouse_id: string;
  warehouse_location_id: string;
};

const emptyForm: WashingForm = {
  lot_id: "",
  washing_place_id: "",
  washing_cost: "",
  duration_hours: "24",
  receipt_file: null
};

const emptyCompleteForm: CompleteForm = {
  after_qty: "",
  grade_id: "",
  warehouse_id: "",
  warehouse_location_id: ""
};

async function parseJsonResponse<T>(response: Response, context: string): Promise<T> {
  const responseText = await response.text();
  if (responseText.trim().length === 0) {
    throw new Error(`${context}: respons kosong`);
  }

  try {
    return JSON.parse(responseText) as T;
  } catch {
    const preview = responseText.slice(0, 160);
    throw new Error(`${context}: server mengembalikan data non-JSON (${preview})`);
  }
}

export function WashingClient({ currencyCode }: { currencyCode: string }) {
  const { dict, locale } = useLocale();
  const searchParams = useSearchParams();
  const requestedId = searchParams.get("id");
  const [washings, setWashings] = useState<WashingListItem[]>([]);
  const [lots, setLots] = useState<LotListItem[]>([]);
  const [washingPlaces, setWashingPlaces] = useState<WashingPlaceRecord[]>([]);
  const [itemGrades, setItemGrades] = useState<GradeRecord[]>([]);
  const [warehouses, setWarehouses] = useState<WarehouseRecord[]>([]);
  const [locations, setLocations] = useState<WarehouseLocationRecord[]>([]);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [completing, setCompleting] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [editingId, setEditingId] = useState<string | null>(null);
  const [completingId, setCompletingId] = useState<string | null>(null);
  const [form, setForm] = useState<WashingForm>(emptyForm);
  const [completeForm, setCompleteForm] = useState<CompleteForm>(emptyCompleteForm);

  async function loadAll() {
    setLoading(true);
    setError(null);
    try {
      const [washingsRes, lotsRes, washingPlacesRes, itemGradesRes, warehousesRes, locationsRes] =
        await Promise.all([
          fetch("/api/v1/washing", { cache: "no-store" }),
          fetch("/api/v1/lots", { cache: "no-store" }),
          fetch("/api/v1/washing-places", { cache: "no-store" }),
          fetch("/api/v1/grades", { cache: "no-store" }),
          fetch("/api/v1/warehouses", { cache: "no-store" }),
          fetch("/api/v1/warehouse-locations", { cache: "no-store" })
        ]);

      const washingsPayload = await parseJsonResponse<{ data: WashingListItem[] } | ApiErrorResponse>(
        washingsRes,
        dict.washingModule.loadError
      );
      const lotsPayload = await parseJsonResponse<{ data: LotListItem[] } | ApiErrorResponse>(
        lotsRes,
        "Memuat lot"
      );
      const washingPlacesPayload = await parseJsonResponse<{ data: WashingPlaceRecord[] } | ApiErrorResponse>(
        washingPlacesRes,
        "Memuat tempat cuci"
      );
      const itemGradesPayload = await parseJsonResponse<{ data: GradeRecord[] } | ApiErrorResponse>(
        itemGradesRes,
        "Memuat grade"
      );
      const warehousesPayload = await parseJsonResponse<{ data: WarehouseRecord[] } | ApiErrorResponse>(
        warehousesRes,
        "Memuat gudang"
      );
      const locationsPayload = await parseJsonResponse<
        { data: WarehouseLocationRecord[] } | ApiErrorResponse
      >(locationsRes, "Memuat lokasi gudang");

      if (
        !washingsRes.ok ||
        !lotsRes.ok ||
        !washingPlacesRes.ok ||
        !itemGradesRes.ok ||
        !warehousesRes.ok ||
        !locationsRes.ok ||
        !("data" in washingsPayload) ||
        !("data" in lotsPayload) ||
        !("data" in washingPlacesPayload) ||
        !("data" in itemGradesPayload) ||
        !("data" in warehousesPayload) ||
        !("data" in locationsPayload)
      ) {
        throw new Error(dict.common.requestFailed);
      }

      setWashings(washingsPayload.data);
      setLots(lotsPayload.data);
      setWashingPlaces(washingPlacesPayload.data.filter((item) => item.status === "ACTIVE"));
      setItemGrades(itemGradesPayload.data.filter((item) => item.status === "ACTIVE"));
      setWarehouses(warehousesPayload.data.filter((item) => item.status === "ACTIVE"));
      setLocations(locationsPayload.data.filter((item) => item.status === "ACTIVE"));
    } catch (err) {
      setError(err instanceof Error ? err.message : dict.common.requestFailed);
    } finally {
      setLoading(false);
    }
  }

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

  useEffect(() => {
    if (!requestedId || editingId === requestedId) return;
    const requestedWashing = washings.find((item) => item.id === requestedId);
    if (requestedWashing) {
      startEdit(requestedWashing);
    }
  }, [editingId, requestedId, washings]);

  const inProgressLotIds = useMemo(
    () =>
      new Set(
        washings
          .filter((item) => item.status === "IN_PROGRESS")
          .map((item) => item.lot.id)
      ),
    [washings]
  );

  const selectableLots = useMemo(() => {
    const editingLotId = editingId
      ? washings.find((item) => item.id === editingId)?.lot.id ?? null
      : null;

    return lots.filter(
      (lot) =>
        lot.status === "ACTIVE" &&
        lot.available_qty > 0 &&
        (!inProgressLotIds.has(lot.id) || editingLotId === lot.id)
    );
  }, [editingId, inProgressLotIds, lots, washings]);

  const selectedLot = useMemo(
    () => selectableLots.find((item) => item.id === form.lot_id) ?? null,
    [form.lot_id, selectableLots]
  );

  const completingItem = useMemo(
    () => washings.find((item) => item.id === completingId) ?? null,
    [completingId, washings]
  );

  const filteredLocations = useMemo(
    () => locations.filter((item) => item.warehouse_id === completeForm.warehouse_id),
    [completeForm.warehouse_id, locations]
  );

  function resetForm() {
    setEditingId(null);
    setForm(emptyForm);
  }

  function startEdit(item: WashingListItem) {
    setEditingId(item.id);
    setCompletingId(null);
    setForm({
      lot_id: item.lot.id,
      washing_place_id: item.washing_place.id,
      washing_cost: String(item.washing_cost),
      duration_hours: String(item.duration_hours),
      receipt_file: null
    });
    setError(null);
  }

  function startComplete(item: WashingListItem) {
    setCompletingId(item.id);
    setEditingId(null);
    setCompleteForm({
      after_qty: String(item.lot.available_qty),
      grade_id: "",
      warehouse_id: "",
      warehouse_location_id: ""
    });
    setError(null);
  }

  async function saveWashing() {
    setSaving(true);
    setError(null);
    try {
      const formData = new FormData();
      formData.append(
        "payload",
        JSON.stringify({
          lot_id: form.lot_id,
          washing_place_id: form.washing_place_id,
          washing_cost: Number(form.washing_cost || 0),
          duration_hours: Number(form.duration_hours || 0)
        })
      );
      if (form.receipt_file) {
        formData.append("receipt_file", form.receipt_file);
      }

      const response = await fetch(editingId ? `/api/v1/washing/${editingId}` : "/api/v1/washing", {
        method: editingId ? "PUT" : "POST",
        body: formData
      });
      const result = await parseJsonResponse<DetailResponse<WashingListItem> | ApiErrorResponse>(
        response,
        dict.washingModule.saveError
      );
      if (!response.ok || !("data" in result)) {
        const validationMessage =
          "errors" in result && result.errors
            ? Object.values(result.errors)[0]?.[0]
            : null;
        throw new Error(
          validationMessage ?? ("message" in result ? result.message : dict.washingModule.saveError)
        );
      }

      resetForm();
      await loadAll();
    } catch (err) {
      setError(err instanceof Error ? err.message : dict.washingModule.saveError);
    } finally {
      setSaving(false);
    }
  }

  async function completeWashing() {
    if (!completingId) return;
    setCompleting(true);
    setError(null);
    try {
      const response = await fetch(`/api/v1/washing/${completingId}/complete`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify({
          after_qty: Number(completeForm.after_qty || 0),
          grade_id: completeForm.grade_id || null,
          warehouse_id: completeForm.warehouse_id,
          warehouse_location_id: completeForm.warehouse_location_id || null
        })
      });
      const result = await parseJsonResponse<DetailResponse<WashingListItem> | ApiErrorResponse>(
        response,
        dict.washingModule.completeError
      );
      if (!response.ok || !("data" in result)) {
        const validationMessage =
          "errors" in result && result.errors
            ? Object.values(result.errors)[0]?.[0]
            : null;
        throw new Error(
          validationMessage ?? ("message" in result ? result.message : dict.washingModule.completeError)
        );
      }

      setCompletingId(null);
      setCompleteForm(emptyCompleteForm);
      await loadAll();
    } catch (err) {
      setError(err instanceof Error ? err.message : dict.washingModule.completeError);
    } finally {
      setCompleting(false);
    }
  }

  return (
    <section className="space-y-6">
      <div className="ops-card p-6">
        <div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
          <div>
            <p className="ops-overline">{dict.washingModule.overline}</p>
            <h2 className="mt-2 text-[32px] font-semibold tracking-tight text-ink">{dict.washingModule.title}</h2>
            <p className="mt-3 text-[14px] leading-6 text-slate-500">
              {dict.washingModule.helper}
            </p>
          </div>
          {selectedLot ? (
            <div className="rounded-xl border border-line/70 bg-slate-50 px-4 py-3 text-sm text-slate-600">
              {dict.washingModule.lotSelected}: <span className="font-semibold text-ink">{selectedLot.lot_code}</span> · {selectedLot.available_qty} {selectedLot.unit_code}
            </div>
          ) : null}
        </div>
        {error ? <div className="mt-5 rounded border border-ember/30 bg-ember/10 px-4 py-3 text-sm text-ember">{error}</div> : null}
      </div>

      <div className="grid gap-6 xl:grid-cols-[0.95fr_1.05fr]">
        <div className="ops-card p-6">
          <div className="flex items-center justify-between gap-4">
            <div>
              <p className="ops-title">{editingId ? dict.washingModule.editTitle : dict.washingModule.createTitle}</p>
              <p className="ops-copy">{dict.washingModule.receiptHint}</p>
            </div>
            {editingId ? (
              <button type="button" onClick={resetForm} className="ops-btn-secondary">
                {dict.common.cancelEdit}
              </button>
            ) : null}
          </div>

          <div className="mt-6 grid gap-4 md:grid-cols-2">
            <SelectField
              label={dict.washingModule.lot}
              value={form.lot_id}
              onChange={(value) => setForm((current) => ({ ...current, lot_id: value }))}
              options={selectableLots.map((lot) => ({
                value: lot.id,
                label: `${lot.lot_code} · ${lot.grade} · ${lot.available_qty} ${lot.unit_code}`
              }))}
              disabled={Boolean(editingId)}
            />
            <SelectField
              label={dict.washingModule.washingPlace}
              value={form.washing_place_id}
              onChange={(value) => setForm((current) => ({ ...current, washing_place_id: value }))}
              options={washingPlaces.map((item) => ({
                value: item.id,
                label: `${item.code} - ${item.name}`
              }))}
            />
            <Field
              label={dict.washingModule.cost}
              value={form.washing_cost}
              onChange={(value) => setForm((current) => ({ ...current, washing_cost: value }))}
              inputMode="decimal"
            />
            <Field
              label={dict.washingModule.duration}
              value={form.duration_hours}
              onChange={(value) => setForm((current) => ({ ...current, duration_hours: value }))}
              inputMode="numeric"
            />
            <label className="block md:col-span-2">
              <span className="ops-label">{dict.washingModule.receipt}</span>
              <input
                type="file"
                accept=".jpg,.jpeg,.png,.pdf"
                onChange={(event) =>
                  setForm((current) => ({
                    ...current,
                    receipt_file: event.target.files?.[0] ?? null
                  }))
                }
                className="ops-input file:mr-3 file:rounded-md file:border-0 file:bg-moss/10 file:px-3 file:py-2 file:text-sm file:font-medium file:text-moss"
              />
            </label>
          </div>

          <div className="mt-6 flex justify-end">
            <button type="button" onClick={() => void saveWashing()} disabled={saving} className="ops-btn-primary">
              {saving ? dict.common.processing : dict.common.save}
            </button>
          </div>
        </div>

        {completingItem ? (
          <div className="ops-card p-6">
            <div className="flex items-center justify-between gap-4">
              <div>
                <p className="ops-title">Selesai Cuci</p>
                <p className="ops-copy">
                  {completingItem.washing_no} · {completingItem.lot.lot_code} · {dict.washingModule.startingQty} {completingItem.before_qty} {completingItem.lot.unit_code}
                </p>
              </div>
              <button
                type="button"
                onClick={() => {
                  setCompletingId(null);
                  setCompleteForm(emptyCompleteForm);
                }}
                className="ops-btn-secondary"
              >
                {dict.common.cancel}
              </button>
            </div>

            <div className="mt-6 grid gap-4 md:grid-cols-2">
              <Field
                label={dict.washingModule.afterQty}
                value={completeForm.after_qty}
                onChange={(value) => setCompleteForm((current) => ({ ...current, after_qty: value }))}
                inputMode="decimal"
              />
              <SearchableSelectField
                label="Ubah Grade (opsional)"
                value={completeForm.grade_id}
                onChange={(value) => setCompleteForm((current) => ({ ...current, grade_id: value }))}
                options={itemGrades.map((item) => ({
                  value: item.id,
                  label: `${item.code} - ${item.name}`
                }))}
                placeholder={locale === "id" ? "Tidak diubah" : "No change"}
                searchPlaceholder={locale === "id" ? "Cari grade..." : "Search grade..."}
              />
              <SelectField
                label={dict.washingModule.destinationWarehouse}
                value={completeForm.warehouse_id}
                onChange={(value) =>
                  setCompleteForm((current) => ({
                    ...current,
                    warehouse_id: value,
                    warehouse_location_id: ""
                  }))
                }
                options={warehouses.map((item) => ({
                  value: item.id,
                  label: `${item.code} - ${item.name}`
                }))}
              />
              <SelectField
                label={dict.washingModule.warehouseLocation}
                value={completeForm.warehouse_location_id}
                onChange={(value) => setCompleteForm((current) => ({ ...current, warehouse_location_id: value }))}
                options={filteredLocations.map((item) => ({
                  value: item.id,
                  label: `${item.code} - ${item.name}`
                }))}
                allowEmpty
              />
            </div>

            <div className="mt-6 flex justify-end">
              <button type="button" onClick={() => void completeWashing()} disabled={completing} className="ops-btn-primary">
                {completing ? dict.common.processing : dict.washingModule.saveCompletion}
              </button>
            </div>
          </div>
        ) : (
          <div className="ops-card p-6 text-sm text-slate-500">
            {dict.washingModule.completionHint}
          </div>
        )}
      </div>

      <div className="ops-table-shell">
        <div className="ops-section-head">
          <div>
            <p className="ops-title">{dict.washingModule.listTitle}</p>
            <p className="ops-copy">{dict.washingModule.listCopy}</p>
          </div>
          <div className="ops-chip-muted">{washings.length} {dict.washingModule.countSuffix}</div>
        </div>

        {loading ? (
          <div className="px-6 py-8 text-sm text-ink/60">{dict.common.loading}</div>
        ) : washings.length === 0 ? (
          <div className="px-6 py-8 text-sm text-ink/60">{dict.washingModule.noData}</div>
        ) : (
          <div className="overflow-x-auto">
            <table className="ops-table">
              <thead>
                <tr>
                  <th>{dict.washingModule.processColumn}</th>
                  <th>Lot</th>
                  <th>{dict.washingModule.placeColumn}</th>
                  <th>{dict.washingModule.qtyColumn}</th>
                  <th>{dict.washingModule.costColumn}</th>
                  <th>{dict.common.status}</th>
                  <th>{dict.common.actions}</th>
                </tr>
              </thead>
              <tbody>
                {washings.map((item) => (
                  <tr key={item.id}>
                    <td>
                      <div className="font-semibold text-ink">{item.washing_no}</div>
                      <div className="mt-1 text-xs text-slate-500">
                        {new Date(item.started_at).toLocaleString(locale === "id" ? "id-ID" : "en-US")} · {item.duration_hours} jam
                      </div>
                    </td>
                    <td className="text-slate-600">
                      <div className="font-medium text-ink">{item.lot.lot_code}</div>
                      <div className="mt-1 text-xs">{item.lot.grade_name ?? "-"}</div>
                      <div className="mt-1 text-xs">{item.lot.supplier}</div>
                    </td>
                    <td className="text-slate-600">
                      <div>{item.washing_place.name}</div>
                      {item.receipt_file_url ? (
                        <Link href={item.receipt_file_url} target="_blank" className="mt-1 inline-block text-xs text-moss underline">
                          {dict.washingModule.viewReceipt}
                        </Link>
                      ) : (
                        <div className="mt-1 text-xs">{dict.washingModule.noReceipt}</div>
                      )}
                    </td>
                    <td className="text-slate-600">
                      <div>Awal: {item.before_qty} {item.lot.unit_code}</div>
                      <div className="mt-1 text-xs">
                        {item.after_qty === null ? dict.washingModule.notDone : `${dict.washingModule.finalQty}: ${item.after_qty} ${item.lot.unit_code}`}
                      </div>
                    </td>
                    <td className="text-slate-600">
                      {formatCurrencyAmount(item.washing_cost, locale, currencyCode, 0)}
                    </td>
                    <td>
                      <span className={item.status === "DONE" ? "ops-chip-active" : "ops-chip-muted"}>
                        {item.status}
                      </span>
                    </td>
                    <td>
                      <div className="flex flex-wrap gap-2">
                        {item.status !== "DONE" ? (
                          <>
                            <button type="button" onClick={() => startEdit(item)} className="ops-btn-secondary">
                              {dict.common.edit}
                            </button>
                            <button type="button" onClick={() => startComplete(item)} className="ops-btn-primary">
                              {dict.washingModule.doneAction}
                            </button>
                          </>
                        ) : (
                          <span className="text-xs text-slate-500">
                            {dict.washingModule.shrinkage} {item.shrinkage_qty ?? 0} {item.lot.unit_code}
                          </span>
                        )}
                      </div>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        )}
      </div>
    </section>
  );
}

function Field({
  label,
  value,
  onChange,
  inputMode = "text"
}: {
  label: string;
  value: string;
  onChange: (value: string) => void;
  inputMode?: HTMLAttributes<HTMLInputElement>["inputMode"];
}) {
  return (
    <label className="block">
      <span className="ops-label">{label}</span>
      <input value={value} onChange={(event) => onChange(event.target.value)} inputMode={inputMode} className="ops-input" />
    </label>
  );
}

function SelectField({
  label,
  value,
  onChange,
  options,
  allowEmpty = false,
  disabled = false
}: {
  label: string;
  value: string;
  onChange: (value: string) => void;
  options: Array<{ value: string; label: string }>;
  allowEmpty?: boolean;
  disabled?: boolean;
}) {
  const { locale } = useLocale();
  return (
    <label className="block">
      <span className="ops-label">{label}</span>
      <select value={value} onChange={(event) => onChange(event.target.value)} className="ops-select" disabled={disabled}>
        <option value="">
          {allowEmpty
            ? locale === "id"
              ? "Tidak diubah"
              : "No change"
            : locale === "id"
              ? "Pilih"
              : "Choose"}
        </option>
        {options.map((item) => (
          <option key={item.value} value={item.value}>
            {item.label}
          </option>
        ))}
      </select>
    </label>
  );
}
