"use client";
import { useEffect, useMemo, useState, type FormEvent } from "react";
import { useSearchParams } from "next/navigation";
import { Field } from "@/components/shared/field";
import { DataTable, type Column } from "@/components/shared/data-table";
import { PreviewNotice } from "@/components/shared/page";
import { Tabs } from "@/components/shared/tabs";
import { Button } from "@/components/ui/button";
import { useDashboardAuth } from "@/components/layout/dashboard-auth-context";
import { usePreviewRole } from "@/components/layout/preview-context";
import { canManage } from "@/lib/preview";
import {
  getLoyaltySettings,
  getLoyaltyTenantLedger,
  initialLoyaltySettings,
  updateLoyaltySettings,
  type LoyaltyLedgerRow,
  type LoyaltySettings,
} from "./api-client";

type SettingsDraft = Record<keyof LoyaltySettings, string>;
type LoadState = "loading" | "loaded" | "failed";

function toDraft(settings: LoyaltySettings): SettingsDraft {
  return {
    pointsPerKwh: String(settings.pointsPerKwh),
    pointsPerIdr: String(settings.pointsPerIdr),
    pointValueIdr: String(settings.pointValueIdr),
    minRedeemPoints: String(settings.minRedeemPoints),
  };
}

function parseDraft(draft: SettingsDraft): LoyaltySettings | null {
  const entries = Object.entries(draft).map(([key, value]) => [key, Number(value)] as const);
  if (entries.some(([, value]) => !Number.isFinite(value) || value < 0)) {
    return null;
  }
  const values = Object.fromEntries(entries) as LoyaltySettings;
  if (!Number.isSafeInteger(values.minRedeemPoints)) return null;
  return values;
}

function titleForKey(value: string) {
  return value
    .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
    .replaceAll("_", " ")
    .replaceAll("-", " ")
    .replace(/\b\w/g, (letter) => letter.toUpperCase());
}

export function LoyaltyManagement() {
  const params = useSearchParams();
  const { apiConfigured } = useDashboardAuth();
  const manage = canManage(usePreviewRole());
  const tab = params.get("tab") === "ledger" ? "ledger" : "settings";
  const [draft, setDraft] = useState(() => toDraft(initialLoyaltySettings));
  const [settingsState, setSettingsState] = useState<LoadState>(
    apiConfigured ? "loading" : "loaded",
  );
  const [settingsError, setSettingsError] = useState("");
  const [settingsReloadKey, setSettingsReloadKey] = useState(0);
  const [saving, setSaving] = useState(false);
  const [notice, setNotice] = useState("");
  const [formError, setFormError] = useState("");
  const [ledgerRows, setLedgerRows] = useState<LoyaltyLedgerRow[]>([]);
  const [ledgerTotal, setLedgerTotal] = useState(0);
  const [ledgerState, setLedgerState] = useState<LoadState>(
    apiConfigured && tab === "ledger" ? "loading" : "loaded",
  );
  const [ledgerError, setLedgerError] = useState("");
  const [ledgerReloadKey, setLedgerReloadKey] = useState(0);

  useEffect(() => {
    if (!apiConfigured) return;
    const controller = new AbortController();
    async function loadSettings() {
      setSettingsState("loading");
      setSettingsError("");
      try {
        const value = await getLoyaltySettings(controller.signal);
        if (controller.signal.aborted) return;
        setDraft(toDraft(value));
        setSettingsState("loaded");
      } catch (error: unknown) {
        if (controller.signal.aborted) return;
        setSettingsState("failed");
        setSettingsError(
          error instanceof Error
            ? error.message
            : "Could not load loyalty settings.",
        );
      }
    }
    void loadSettings();
    return () => controller.abort();
  }, [apiConfigured, settingsReloadKey]);

  useEffect(() => {
    if (!apiConfigured || tab !== "ledger") return;
    const controller = new AbortController();
    async function loadLedger() {
      setLedgerState("loading");
      setLedgerError("");
      try {
        const result = await getLoyaltyTenantLedger(controller.signal);
        if (controller.signal.aborted) return;
        setLedgerRows(result.rows);
        setLedgerTotal(result.total);
        setLedgerState("loaded");
      } catch (error: unknown) {
        if (controller.signal.aborted) return;
        setLedgerRows([]);
        setLedgerState("failed");
        setLedgerError(
          error instanceof Error
            ? error.message
            : "Could not load the tenant ledger.",
        );
      }
    }
    void loadLedger();
    return () => controller.abort();
  }, [apiConfigured, tab, ledgerReloadKey]);

  const ledgerColumns = useMemo<Column<LoyaltyLedgerRow>[]>(() => {
    const keys = new Set<string>(["id"]);
    for (const row of ledgerRows) {
      for (const key of Object.keys(row)) keys.add(key);
    }
    return [...keys].map((key) => ({
      key,
      label: titleForKey(key),
    }));
  }, [ledgerRows]);

  async function saveSettings(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    setNotice("");
    setFormError("");
    if (!manage || saving || settingsState !== "loaded") return;
    const parsed = parseDraft(draft);
    if (!parsed) {
      setFormError("Enter non-negative values and a whole number for minimum redemption points.");
      return;
    }

    setSaving(true);
    try {
      const saved = apiConfigured
        ? await updateLoyaltySettings(parsed)
        : parsed;
      setDraft(toDraft(saved));
      setNotice(
        apiConfigured
          ? "Loyalty settings updated."
          : "Saved in local preview. No API request was made.",
      );
    } catch (error: unknown) {
      setFormError(
        error instanceof Error
          ? error.message
          : "Could not update loyalty settings.",
      );
    } finally {
      setSaving(false);
    }
  }

  return (
    <div className="space-y-5">
      <Tabs
        queryKey="tab"
        items={[
          { value: "settings", label: "Loyalty Settings" },
          { value: "ledger", label: "Tenant Ledger" },
        ]}
      />

      {tab === "settings" ? (
        <section className="panel space-y-5 p-5">
          <div>
            <h2 className="font-semibold">Point earning and redemption</h2>
            <p className="mt-1 text-sm text-muted-foreground">
              Configure how charging and spending affect loyalty points.
            </p>
          </div>
          {!apiConfigured && (
            <PreviewNotice>
              Preview settings start from the sample values and stay local to this page.
            </PreviewNotice>
          )}
          {settingsState === "loading" ? (
            <p role="status" className="text-sm text-muted-foreground">
              Loading loyalty settings…
            </p>
          ) : settingsState === "failed" ? (
            <div role="alert" className="space-y-3">
              <p className="text-sm text-destructive">{settingsError}</p>
              <Button
                variant="outline"
                onClick={() => setSettingsReloadKey((current) => current + 1)}
              >
                Try again
              </Button>
            </div>
          ) : (
            <form onSubmit={saveSettings} className="space-y-5">
              <div className="grid gap-4 sm:grid-cols-2">
                <div className="space-y-1.5">
                  <Field
                    label="Points per kWh"
                    type="number"
                    min="0"
                    step="any"
                    value={draft.pointsPerKwh}
                    disabled={!manage || saving}
                    onChange={(event) =>
                      setDraft((current) => ({
                        ...current,
                        pointsPerKwh: event.target.value,
                      }))
                    }
                  />
                  <p className="text-xs text-muted-foreground">
                    Points awarded for each kWh charged.
                  </p>
                </div>
                <div className="space-y-1.5">
                  <Field
                    label="Points per IDR spent"
                    type="number"
                    min="0"
                    step="any"
                    value={draft.pointsPerIdr}
                    disabled={!manage || saving}
                    onChange={(event) =>
                      setDraft((current) => ({
                        ...current,
                        pointsPerIdr: event.target.value,
                      }))
                    }
                  />
                  <p className="text-xs text-muted-foreground">
                    Points awarded for each IDR spent.
                  </p>
                </div>
                <div className="space-y-1.5">
                  <Field
                    label="Point value (IDR)"
                    type="number"
                    min="0"
                    step="any"
                    value={draft.pointValueIdr}
                    disabled={!manage || saving}
                    onChange={(event) =>
                      setDraft((current) => ({
                        ...current,
                        pointValueIdr: event.target.value,
                      }))
                    }
                  />
                  <p className="text-xs text-muted-foreground">
                    IDR value assigned to one point.
                  </p>
                </div>
                <div className="space-y-1.5">
                  <Field
                    label="Minimum points to redeem"
                    type="number"
                    min="0"
                    step="1"
                    value={draft.minRedeemPoints}
                    disabled={!manage || saving}
                    onChange={(event) =>
                      setDraft((current) => ({
                        ...current,
                        minRedeemPoints: event.target.value,
                      }))
                    }
                  />
                  <p className="text-xs text-muted-foreground">
                    Minimum point balance required for a redemption.
                  </p>
                </div>
              </div>
              {notice && (
                <p role="status" className="text-sm text-success">
                  {notice}
                </p>
              )}
              {formError && (
                <p role="alert" className="text-sm text-destructive">
                  {formError}
                </p>
              )}
              <Button type="submit" disabled={!manage || saving}>
                {saving ? "Saving…" : "Save loyalty settings"}
              </Button>
            </form>
          )}
        </section>
      ) : (
        <section className="space-y-4">
          <div className="flex flex-wrap items-center justify-between gap-3">
            <div>
              <h2 className="font-semibold">Tenant Ledger</h2>
              <p className="mt-1 text-sm text-muted-foreground">
                Loyalty point entries returned by the tenant ledger endpoint.
              </p>
            </div>
            {apiConfigured && (
              <Button
                variant="outline"
                disabled={ledgerState === "loading"}
                onClick={() => setLedgerReloadKey((current) => current + 1)}
              >
                Refresh ledger
              </Button>
            )}
          </div>
          {!apiConfigured ? (
            <PreviewNotice>
              The tenant ledger is available when the Monet API is configured. No ledger rows are simulated in preview.
            </PreviewNotice>
          ) : ledgerState === "loading" ? (
            <p role="status" className="panel p-5 text-sm text-muted-foreground">
              Loading tenant ledger…
            </p>
          ) : ledgerState === "failed" ? (
            <p role="alert" className="panel p-5 text-sm text-destructive">
              {ledgerError}
            </p>
          ) : (
            <DataTable
              title="Tenant Ledger"
              description={`${ledgerRows.length} rows returned${ledgerTotal > ledgerRows.length ? ` · ${ledgerTotal} total in service` : ""}.`}
              rows={ledgerRows}
              columns={ledgerColumns}
              emptyMessage="No loyalty ledger entries found."
            />
          )}
        </section>
      )}
    </div>
  );
}
