"use client";
import { useCallback, useEffect, useState, type FormEvent } from "react";
import { Trash2 } from "lucide-react";
import { DataTable } from "@/components/shared/data-table";
import { PageHeader } from "@/components/shared/page";
import {
  Field,
  SelectField,
  TextareaField,
} from "@/components/shared/field";
import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
  DialogFooter,
} from "@/components/ui/dialog";
import { canManage } from "@/lib/preview";
import { usePreviewRole } from "@/components/layout/preview-context";
import {
  createVoucher,
  deleteVoucher,
  getVouchers,
  voucherRewardOptions,
  voucherVisibilityOptions,
  type CreateVoucherPayload,
  type MonetVoucher,
  type VoucherRewardType,
  type VoucherVisibility,
} from "./api-client";

type VoucherDraft = {
  code: string;
  name: string;
  type: VoucherVisibility;
  locationIds: string;
  userIds: string;
  rewardType: VoucherRewardType;
  targetEnergyPrice: string;
  startClaimDatetime: string;
  endClaimDatetime: string;
  startRedeemDatetime: string;
  endRedeemDatetime: string;
  maxUsagePerUser: string;
  maxClaimPerUser: string;
  maxRedeemPerClaim: string;
};

const emptyVoucherDraft: VoucherDraft = {
  code: "",
  name: "",
  type: "PUBLIC",
  locationIds: "",
  userIds: "",
  rewardType: "SERVICE_FEE_WAIVER",
  targetEnergyPrice: "",
  startClaimDatetime: "",
  endClaimDatetime: "",
  startRedeemDatetime: "",
  endRedeemDatetime: "",
  maxUsagePerUser: "0",
  maxClaimPerUser: "0",
  maxRedeemPerClaim: "1",
};

function idList(value: string): string[] | null {
  const ids = value
    .split(/[\n,]/)
    .map((entry) => entry.trim())
    .filter(Boolean);
  const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
  if (ids.length > 100 || ids.some((id) => !uuid.test(id))) return null;
  return [...new Set(ids)];
}

function formDate(value: string): string | null {
  const date = new Date(value);
  return Number.isFinite(date.getTime()) ? date.toISOString() : null;
}

function createPayload(draft: VoucherDraft): {
  payload?: CreateVoucherPayload;
  error?: string;
} {
  const code = draft.code.trim();
  const name = draft.name.trim();
  if (!/^[A-Za-z0-9_-]{1,64}$/.test(code)) {
    return { error: "Use 1–64 letters, numbers, underscores, or hyphens for the code." };
  }
  if (!name || name.length > 255) {
    return { error: "Enter a voucher name of up to 255 characters." };
  }
  const locationIds = idList(draft.locationIds);
  const userIds = idList(draft.userIds);
  if (!locationIds || !userIds) {
    return { error: "Enter valid UUIDs for location and user IDs (up to 100 each)." };
  }
  const startClaimDatetime = formDate(draft.startClaimDatetime);
  const endClaimDatetime = formDate(draft.endClaimDatetime);
  const startRedeemDatetime = formDate(draft.startRedeemDatetime);
  const endRedeemDatetime = formDate(draft.endRedeemDatetime);
  if (!startClaimDatetime || !endClaimDatetime || !startRedeemDatetime || !endRedeemDatetime) {
    return { error: "Enter valid claim and redemption dates." };
  }
  if (
    Date.parse(startClaimDatetime) >= Date.parse(endClaimDatetime) ||
    Date.parse(startRedeemDatetime) >= Date.parse(endRedeemDatetime)
  ) {
    return { error: "Each end date must follow its start date." };
  }
  const maxUsagePerUser = Number(draft.maxUsagePerUser);
  const maxClaimPerUser = Number(draft.maxClaimPerUser);
  const maxRedeemPerClaim = Number(draft.maxRedeemPerClaim);
  if (
    !Number.isSafeInteger(maxUsagePerUser) ||
    maxUsagePerUser < 0 ||
    !Number.isSafeInteger(maxClaimPerUser) ||
    maxClaimPerUser < 0 ||
    !Number.isSafeInteger(maxRedeemPerClaim) ||
    maxRedeemPerClaim < 1
  ) {
    return { error: "Limits must be whole numbers; redeem per claim must be at least 1." };
  }
  const payload: CreateVoucherPayload = {
    code,
    name,
    type: draft.type,
    location_ids: locationIds,
    user_ids: userIds,
    reward_type: draft.rewardType,
    start_claim_datetime: startClaimDatetime,
    end_claim_datetime: endClaimDatetime,
    start_redeem_datetime: startRedeemDatetime,
    end_redeem_datetime: endRedeemDatetime,
    max_usage_per_user: maxUsagePerUser,
    max_claim_per_user: maxClaimPerUser,
    max_redeem_per_claim: maxRedeemPerClaim,
  };
  if (draft.rewardType === "ENERGY_PRICE_SUBSIDY") {
    const targetEnergyPrice = Number(draft.targetEnergyPrice);
    if (!Number.isFinite(targetEnergyPrice) || targetEnergyPrice <= 0) {
      return { error: "Enter a target energy price greater than zero." };
    }
    payload.target_energy_price = targetEnergyPrice;
  }
  return { payload };
}

function dateLabel(value: string): string {
  if (!value) return "—";
  const date = new Date(value);
  return Number.isFinite(date.getTime()) ? date.toLocaleString() : value;
}

function rewardLabel(voucher: MonetVoucher): string {
  const label = voucher.rewardType.replaceAll("_", " ");
  return voucher.targetEnergyPrice
    ? `${label} · ${voucher.targetEnergyPrice}`
    : label;
}

export function VouchersView() {
  const canEdit = canManage(usePreviewRole());
  const [vouchers, setVouchers] = useState<MonetVoucher[]>([]),
    [voucher, setVoucher] = useState<VoucherDraft | null>(null),
    [deletingVoucherId, setDeletingVoucherId] = useState<string | null>(null),
    [error, setError] = useState(""),
    [loadError, setLoadError] = useState(""),
    [loadingVouchers, setLoadingVouchers] = useState(true),
    [savingVoucher, setSavingVoucher] = useState(false),
    [deletingVoucher, setDeletingVoucher] = useState(false),
    [notice, setNotice] = useState("");
  const refreshVouchers = useCallback(async (signal?: AbortSignal) => {
    setLoadingVouchers(true);
    setLoadError("");
    try {
      const rows = await getVouchers(signal);
      if (signal?.aborted) return false;
      setVouchers(rows);
      return true;
    } catch (cause) {
      if (signal?.aborted) return false;
      setVouchers([]);
      setLoadError(
        cause instanceof Error
          ? cause.message
          : "The Monet service could not load vouchers.",
      );
      return false;
    } finally {
      if (!signal?.aborted) setLoadingVouchers(false);
    }
  }, []);
  useEffect(() => {
    const controller = new AbortController();
    async function loadInitialVouchers() {
      try {
        const rows = await getVouchers(controller.signal);
        if (controller.signal.aborted) return;
        setVouchers(rows);
        setLoadError("");
      } catch (cause) {
        if (controller.signal.aborted) return;
        setVouchers([]);
        setLoadError(
          cause instanceof Error
            ? cause.message
            : "The Monet service could not load vouchers.",
        );
      } finally {
        if (!controller.signal.aborted) setLoadingVouchers(false);
      }
    }
    void loadInitialVouchers();
    return () => controller.abort();
  }, []);

  const changeVoucher = (key: keyof VoucherDraft, value: string) =>
    setVoucher((current) => (current ? { ...current, [key]: value } : current));

  async function saveVoucher(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!voucher) return;
    setError("");
    const result = createPayload(voucher);
    if (!result.payload) {
      setError(result.error ?? "Check the voucher details.");
      return;
    }
    setSavingVoucher(true);
    try {
      await createVoucher(result.payload);
      setVoucher(null);
      const refreshed = await refreshVouchers();
      setNotice(
        refreshed
          ? `Voucher ${result.payload.code} created.`
          : `Voucher ${result.payload.code} was created, but the list could not refresh. Try refreshing the list.`,
      );
    } catch (cause) {
      setError(
        cause instanceof Error ? cause.message : "The voucher could not be created.",
      );
    } finally {
      setSavingVoucher(false);
    }
  }

  async function confirmDelete() {
    if (!deletingVoucherId) return;
    setError("");
    setDeletingVoucher(true);
    try {
      await deleteVoucher(deletingVoucherId);
      setVouchers((all) => all.filter((row) => row.id !== deletingVoucherId));
      setDeletingVoucherId(null);
      setNotice("Voucher deleted.");
    } catch (cause) {
      setError(
        cause instanceof Error ? cause.message : "The voucher could not be deleted.",
      );
    } finally {
      setDeletingVoucher(false);
    }
  }
  return (
    <>
      <PageHeader title="Vouchers" />
      <div className="space-y-5">
        {notice && (
          <p role="status" className="text-success">
            {notice}
          </p>
        )}
        <DataTable
          title="Voucher List"
          rows={vouchers}
          dataState={{
            loading: loadingVouchers,
            error: loadError,
            onRefresh: () => void refreshVouchers(),
          }}
          exportName="vouchers"
          emptyMessage="No vouchers found."
          filters={[
            {
              key: "type",
              label: "Visibility",
              options: [...voucherVisibilityOptions],
            },
          ]}
          onCreate={
            canEdit
              ? () => {
                  setError("");
                  setVoucher({ ...emptyVoucherDraft });
                }
              : undefined
          }
          columns={[
            { key: "code", label: "Code" },
            { key: "name", label: "Name" },
            { key: "type", label: "Visibility" },
            { key: "rewardType", label: "Reward", render: rewardLabel },
            {
              key: "startClaimDatetime",
              label: "Claim Window",
              render: (r) => (
                <span className="block min-w-44 text-xs">
                  {dateLabel(r.startClaimDatetime)}
                  <br />
                  to {dateLabel(r.endClaimDatetime)}
                </span>
              ),
            },
            {
              key: "startRedeemDatetime",
              label: "Redeem Window",
              render: (r) => (
                <span className="block min-w-44 text-xs">
                  {dateLabel(r.startRedeemDatetime)}
                  <br />
                  to {dateLabel(r.endRedeemDatetime)}
                </span>
              ),
            },
            {
              key: "maxUsagePerUser",
              label: "Limits / user",
              render: (r) =>
                `Usage ${r.maxUsagePerUser || "∞"} · Claims ${r.maxClaimPerUser || "∞"} · Redeem ${r.maxRedeemPerClaim}`,
            },
            {
              key: "locationIds",
              label: "Location IDs",
              render: (r) => r.locationIds.length || "—",
            },
            {
              key: "userIds",
              label: "User IDs",
              render: (r) => r.userIds.length || "—",
            },
          ]}
          actions={
            canEdit
              ? (r) => (
                  <Button
                    size="icon"
                    variant="ghost"
                    aria-label={`Delete ${r.code}`}
                    onClick={() => {
                      setError("");
                      setDeletingVoucherId(r.id);
                    }}
                  >
                    <Trash2 className="size-4" />
                  </Button>
                )
              : undefined
          }
        />
      </div>
      <Dialog
        open={!!voucher}
        onOpenChange={(open) => {
          if (!open && !savingVoucher) {
            setVoucher(null);
            setError("");
          }
        }}
      >
        <DialogContent className="max-h-[90dvh] overflow-y-auto">
          <DialogHeader>
            <DialogTitle>Create Voucher</DialogTitle>
            <DialogDescription>
              Create a voucher in Monet. Location and user IDs are optional.
            </DialogDescription>
          </DialogHeader>
          {voucher && (
            <form onSubmit={saveVoucher}>
              <div className="mb-6 grid gap-4 sm:grid-cols-2">
                <Field
                  label="Code"
                  required
                  value={voucher.code}
                  onChange={(e) => changeVoucher("code", e.target.value)}
                  autoComplete="off"
                />
                <Field
                  label="Name"
                  required
                  value={voucher.name}
                  onChange={(e) => changeVoucher("name", e.target.value)}
                />
                <SelectField
                  label="Visibility"
                  options={voucherVisibilityOptions}
                  value={voucher.type}
                  onChange={(e) =>
                    changeVoucher("type", e.target.value as VoucherVisibility)
                  }
                />
                <SelectField
                  label="Reward Type"
                  options={voucherRewardOptions.map((value) => ({
                    value,
                    label: value.replaceAll("_", " "),
                  }))}
                  value={voucher.rewardType}
                  onChange={(e) =>
                    changeVoucher(
                      "rewardType",
                      e.target.value as VoucherRewardType,
                    )
                  }
                />
                {voucher.rewardType === "ENERGY_PRICE_SUBSIDY" && (
                  <Field
                    label="Target Energy Price"
                    type="number"
                    min="0.01"
                    step="0.01"
                    required
                    value={voucher.targetEnergyPrice}
                    onChange={(e) =>
                      changeVoucher("targetEnergyPrice", e.target.value)
                    }
                  />
                )}
                <TextareaField
                  label="Location IDs"
                  placeholder="One UUID per line or comma-separated"
                  value={voucher.locationIds}
                  onChange={(e) => changeVoucher("locationIds", e.target.value)}
                />
                <TextareaField
                  label="User IDs"
                  placeholder="One UUID per line or comma-separated"
                  value={voucher.userIds}
                  onChange={(e) => changeVoucher("userIds", e.target.value)}
                />
                <Field
                  label="Claim Start"
                  type="datetime-local"
                  required
                  value={voucher.startClaimDatetime}
                  onChange={(e) =>
                    changeVoucher("startClaimDatetime", e.target.value)
                  }
                />
                <Field
                  label="Claim End"
                  type="datetime-local"
                  required
                  value={voucher.endClaimDatetime}
                  onChange={(e) =>
                    changeVoucher("endClaimDatetime", e.target.value)
                  }
                />
                <Field
                  label="Redeem Start"
                  type="datetime-local"
                  required
                  value={voucher.startRedeemDatetime}
                  onChange={(e) =>
                    changeVoucher("startRedeemDatetime", e.target.value)
                  }
                />
                <Field
                  label="Redeem End"
                  type="datetime-local"
                  required
                  value={voucher.endRedeemDatetime}
                  onChange={(e) =>
                    changeVoucher("endRedeemDatetime", e.target.value)
                  }
                />
                <Field
                  label="Maximum Uses per User (0 = unlimited)"
                  type="number"
                  min={0}
                  step={1}
                  required
                  value={voucher.maxUsagePerUser}
                  onChange={(e) =>
                    changeVoucher("maxUsagePerUser", e.target.value)
                  }
                />
                <Field
                  label="Maximum Claims per User (0 = unlimited)"
                  type="number"
                  min={0}
                  step={1}
                  required
                  value={voucher.maxClaimPerUser}
                  onChange={(e) =>
                    changeVoucher("maxClaimPerUser", e.target.value)
                  }
                />
                <Field
                  label="Maximum Redeems per Claim"
                  type="number"
                  min={1}
                  step={1}
                  required
                  value={voucher.maxRedeemPerClaim}
                  onChange={(e) =>
                    changeVoucher("maxRedeemPerClaim", e.target.value)
                  }
                />
              </div>
              {error && (
                <p role="alert" className="mb-4 text-destructive">
                  {error}
                </p>
              )}
              <DialogFooter>
                <Button
                  type="button"
                  variant="outline"
                  onClick={() => setVoucher(null)}
                  disabled={savingVoucher}
                >
                  Cancel
                </Button>
                <Button disabled={savingVoucher}>
                  {savingVoucher ? "Creating…" : "Create Voucher"}
                </Button>
              </DialogFooter>
            </form>
          )}
        </DialogContent>
      </Dialog>
      <Dialog
        open={!!deletingVoucherId}
        onOpenChange={(open) => {
          if (!open && !deletingVoucher) {
            setDeletingVoucherId(null);
            setError("");
          }
        }}
      >
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Delete voucher?</DialogTitle>
            <DialogDescription>
              This will permanently delete the voucher in Monet.
            </DialogDescription>
          </DialogHeader>
          {error && (
            <p role="alert" className="text-sm text-destructive">
              {error}
            </p>
          )}
          <DialogFooter>
            <Button
              variant="outline"
              disabled={deletingVoucher}
              onClick={() => setDeletingVoucherId(null)}
            >
              Cancel
            </Button>
            <Button
              variant="destructive"
              disabled={deletingVoucher}
              onClick={() => void confirmDelete()}
            >
              {deletingVoucher ? "Deleting…" : "Delete Voucher"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </>
  );
}
