"use client";

import { isApiSuccess } from "@/lib/api-messages";
import { useEffect, useState } from "react";
import { Check, Plus, X } from "lucide-react";
import { toast } from "sonner";

import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { SettingsSelect } from "@/components/settings/ui/settings-select";
import type { SettingsSelectOption } from "@/components/settings/types";
import { requestDashboardApi } from "@/lib/dashboard-api-client";
import type { NormalizeAssetTypeRow } from "./schema";

type Props = {
  row: NormalizeAssetTypeRow;
  onSaved?: () => void;
  initialOptions: SettingsSelectOption[];
};

export function AssetTypeCell({ row, onSaved, initialOptions }: Props) {
  const [value, setValue] = useState(row.assetTypeId);
  const [draft, setDraft] = useState(row.assetTypeId);
  const [dirty, setDirty] = useState(false);
  const [isSaving, setIsSaving] = useState(false);
  const [isAddOpen, setIsAddOpen] = useState(false);
  const [isCreating, setIsCreating] = useState(false);
  const [newAssetTitle, setNewAssetTitle] = useState("");
  const [options, setOptions] = useState(() =>
    ensureSelectPlaceholder(initialOptions),
  );

  // Sync with refreshed server data, but never while the user has unsaved
  // changes or a save in flight.
  useEffect(() => {
    if (dirty || isSaving) return;

    setValue((prev) => (prev === row.assetTypeId ? prev : row.assetTypeId));
    setDraft((prev) => (prev === row.assetTypeId ? prev : row.assetTypeId));
  }, [row.assetTypeId, dirty, isSaving]);

  const upsertOption = (nextValue: string, nextLabel: string) => {
    setOptions((prev) => {
      const existingIndex = prev.findIndex((item) => item.value === nextValue);

      if (existingIndex >= 0) {
        const next = [...prev];
        next[existingIndex] = { value: nextValue, label: nextLabel };
        return next;
      }

      return [...prev, { value: nextValue, label: nextLabel }];
    });
  };

  const onChange = (next: string) => {
    setDraft(next);
    setDirty(next !== value);
  };

  const save = async () => {
    if (!draft || draft === "please-select") {
      toast.error("Select an asset type");
      return;
    }

    setIsSaving(true);
    try {
      const data = await requestDashboardApi<{
        status?: string;
        message?: string;
      }>({
        url: "/dashboard/master-table/normalize-asset-types/save-asset-definition",
        method: "POST",
        body: {
          assetType: draft,
          bankId: row.bankCode,
          tag: row.tag,
          assetClass: row.assetClass,
        },
        fallbackError: "Asset type could not be saved.",
        validate: (payload) => isApiSuccess(payload),
      });
      setValue(draft);
      setDirty(false);
      toast.success(data.message ?? "Asset type saved");
      onSaved?.();
    } catch (error) {
      toast.error(
        error instanceof Error
          ? error.message
          : "Asset type could not be saved.",
      );
    } finally {
      setIsSaving(false);
    }
  };

  const addNewAssetType = async () => {
    const title = newAssetTitle.trim();
    if (!title) {
      toast.error("Enter an asset type name");
      return;
    }

    setIsCreating(true);
    try {
      const data = await requestDashboardApi<{
        status?: string;
        message?: string;
        data?: { id?: unknown; label?: unknown };
      }>({
        url: "/dashboard/master-table/normalize-asset-types/insert-definition",
        method: "POST",
        body: { name: title },
        fallbackError: "Asset type could not be added.",
        validate: (payload) => isApiSuccess(payload),
      });

      const id = String(data.data?.id ?? "").trim();
      const label = String(data.data?.label ?? title).trim() || title;

      if (!id) {
        throw new Error("Asset type was created but no id was returned.");
      }

      upsertOption(id, label);
      setDraft(id);
      setDirty(id !== value);
      setNewAssetTitle("");
      setIsAddOpen(false);
      toast.success(data.message ?? "Asset type added");
    } catch (error) {
      toast.error(
        error instanceof Error
          ? error.message
          : "Asset type could not be added.",
      );
    } finally {
      setIsCreating(false);
    }
  };

  const cancel = () => {
    setDraft(value);
    setDirty(false);
  };

  return (
    <div className="flex min-w-[220px] flex-col gap-2">
      <div className="flex min-w-[220px] flex-wrap items-center gap-2">
        <SettingsSelect
          className="h-8 min-w-[180px] flex-1"
          value={draft}
          onValueChange={onChange}
          options={options}
          placeholder="Please select"
          disabled={isSaving || isCreating}
        />
        {dirty ? (
          <div className="flex gap-1">
            <Button
              type="button"
              size="icon-sm"
              className="size-7"
              variant="default"
              onClick={() => void save()}
              aria-label="Save asset type"
              disabled={isSaving || isCreating}
            >
              <Check className="size-3.5" />
            </Button>
            <Button
              type="button"
              size="icon-sm"
              className="size-7"
              variant="outline"
              onClick={cancel}
              aria-label="Cancel"
              disabled={isSaving || isCreating}
            >
              <X className="size-3.5" />
            </Button>
          </div>
        ) : null}
        <Button
          type="button"
          size="icon-sm"
          className="size-7"
          variant="outline"
          onClick={() => setIsAddOpen((prev) => !prev)}
          aria-label="Add asset type"
          disabled={isSaving || isCreating}
        >
          <Plus className="size-3.5" />
        </Button>
      </div>

      {isAddOpen ? (
        <div className="flex items-center gap-2">
          <Input
            className="h-8"
            value={newAssetTitle}
            onChange={(e) => setNewAssetTitle(e.target.value)}
            placeholder="Enter new asset type"
            disabled={isSaving || isCreating}
          />
          <Button
            type="button"
            size="sm"
            onClick={() => void addNewAssetType()}
            disabled={isSaving || isCreating}
          >
            Save
          </Button>
        </div>
      ) : null}
    </div>
  );
}

function ensureSelectPlaceholder(options: SettingsSelectOption[]) {
  if (options.some((option) => option.value === "please-select")) {
    return options;
  }

  return [{ value: "please-select", label: "Please select" }, ...options];
}
