import { zodResolver } from "@hookform/resolvers/zod";
import { useMutation } from "@tanstack/react-query";
import { Badge } from "@workspace/ui/components/badge";
import { Button } from "@workspace/ui/components/button";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@workspace/ui/components/dialog";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@workspace/ui/components/form";
import { Input } from "@workspace/ui/components/input";
import { Textarea } from "@workspace/ui/components/textarea";
import { ConfirmButton } from "@workspace/ui/composed/confirm-button";
import {
  ProTable,
  type ProTableActions,
} from "@workspace/ui/composed/pro-table/pro-table";
import {
  approveLotteryClaim,
  getLotteryClaimList,
  markPaidLotteryClaim,
  rejectLotteryClaim,
} from "@workspace/ui/services/admin/lottery";
import { type ReactNode, useRef, useState } from "react";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";
import { z } from "zod";
import { formatDate } from "@/utils/common";

interface ClaimsPanelProps {
  activity: API.LotteryActivity;
}

type TranslateFn = (key: string, defaultValue: string) => string;

const STATUS_META: Record<
  API.LotteryClaimStatus,
  { labelKey: string; labelDefault: string; className: string }
> = {
  pending_claim: {
    labelKey: "claim.statusPending",
    labelDefault: "Awaiting user",
    className: "bg-gray-100 text-gray-600 border-gray-200",
  },
  reviewing: {
    labelKey: "claim.statusReviewing",
    labelDefault: "Reviewing",
    className: "bg-amber-100 text-amber-700 border-amber-200",
  },
  paying: {
    labelKey: "claim.statusPaying",
    labelDefault: "Paying / Shipping",
    className: "bg-blue-100 text-blue-700 border-blue-200",
  },
  paid: {
    labelKey: "claim.statusPaid",
    labelDefault: "Fulfilled",
    className: "bg-emerald-100 text-emerald-700 border-emerald-200",
  },
  rejected: {
    labelKey: "claim.statusRejected",
    labelDefault: "Rejected",
    className: "bg-rose-100 text-rose-700 border-rose-200",
  },
  expired: {
    labelKey: "claim.statusExpired",
    labelDefault: "Expired",
    className: "bg-gray-100 text-gray-500 border-gray-200",
  },
};

function prizeTypeLabel(type: API.LotteryPrizeType, t: TranslateFn): string {
  const labels: Record<string, string> = {
    crypto: t("prize.typeCrypto", "Crypto"),
    physical: t("prize.typePhysical", "Physical"),
    manual_other: t("prize.typeManualOther", "Manual (Other)"),
  };
  return labels[type] ?? type;
}

function ClaimDataCell({ data }: { data?: Record<string, any> }) {
  if (!data || Object.keys(data).length === 0) {
    return <span className="text-muted-foreground">--</span>;
  }
  return (
    <div className="max-w-[240px] space-y-0.5 text-xs">
      {Object.entries(data).map(([key, value]) => (
        <div className="break-all" key={key}>
          <span className="text-muted-foreground">{key}:</span>{" "}
          <span className="font-medium">{String(value)}</span>
        </div>
      ))}
    </div>
  );
}

const rejectSchema = (t: TranslateFn) =>
  z.object({
    reason: z
      .string()
      .trim()
      .min(2, t("claim.reasonRequired", "Please enter a reason"))
      .max(512, t("claim.reasonTooLong", "Reason cannot exceed 512 chars")),
  });

const markPaidSchema = z.object({
  tx_hash: z.string().trim().max(128).optional(),
  delivery_ref: z.string().trim().max(128).optional(),
});

export default function ClaimsPanel({ activity }: ClaimsPanelProps) {
  const { t } = useTranslation("lottery");
  const ref = useRef<ProTableActions>(null);
  const [rejectOpen, setRejectOpen] = useState(false);
  const [paidOpen, setPaidOpen] = useState(false);
  const [currentRow, setCurrentRow] = useState<API.AdminLotteryClaim | null>(
    null
  );

  const rejectForm = useForm<{ reason: string }>({
    resolver: zodResolver(rejectSchema(t)),
    defaultValues: { reason: "" },
  });
  const paidForm = useForm<z.infer<typeof markPaidSchema>>({
    resolver: zodResolver(markPaidSchema),
    defaultValues: { tx_hash: "", delivery_ref: "" },
  });

  const approveMutation = useMutation({
    mutationFn: (id: number) => approveLotteryClaim({ id }),
    onSuccess: () => {
      toast.success(t("claim.approveSuccess", "Claim approved"));
      ref.current?.refresh();
    },
  });

  const rejectMutation = useMutation({
    mutationFn: (body: API.RejectLotteryClaimRequest) =>
      rejectLotteryClaim(body),
    onSuccess: () => {
      toast.success(t("claim.rejectSuccess", "Claim rejected"));
      setRejectOpen(false);
      setCurrentRow(null);
      rejectForm.reset({ reason: "" });
      ref.current?.refresh();
    },
  });

  const paidMutation = useMutation({
    mutationFn: (body: API.MarkPaidLotteryClaimRequest) =>
      markPaidLotteryClaim(body),
    onSuccess: () => {
      toast.success(t("claim.markPaidSuccess", "Marked as fulfilled"));
      setPaidOpen(false);
      setCurrentRow(null);
      paidForm.reset({ tx_hash: "", delivery_ref: "" });
      ref.current?.refresh();
    },
  });

  const statusOptions = (
    Object.keys(STATUS_META) as API.LotteryClaimStatus[]
  ).map((value) => ({
    value,
    label: t(STATUS_META[value].labelKey, STATUS_META[value].labelDefault),
  }));

  const typeOptions = [
    { value: "crypto", label: t("prize.typeCrypto", "Crypto") },
    { value: "physical", label: t("prize.typePhysical", "Physical") },
    {
      value: "manual_other",
      label: t("prize.typeManualOther", "Manual (Other)"),
    },
  ];

  const openReject = (row: API.AdminLotteryClaim) => {
    setCurrentRow(row);
    rejectForm.reset({ reason: "" });
    setRejectOpen(true);
  };
  const openPaid = (row: API.AdminLotteryClaim) => {
    setCurrentRow(row);
    paidForm.reset({ tx_hash: "", delivery_ref: "" });
    setPaidOpen(true);
  };

  return (
    <>
      <ProTable<
        API.AdminLotteryClaim,
        { type?: string; status?: string; user_id?: string }
      >
        action={ref}
        actions={{
          render: (row) => {
            const actions: ReactNode[] = [];
            if (row.status === "reviewing") {
              actions.push(
                <ConfirmButton
                  cancelText={t("claim.cancel", "Cancel")}
                  confirmText={t("claim.confirm", "Confirm")}
                  description={t(
                    "claim.approveDescription",
                    "Approving moves this claim to the paying/shipping stage."
                  )}
                  key="approve"
                  onConfirm={async () => {
                    await approveMutation.mutateAsync(row.id);
                  }}
                  title={t("claim.approveTitle", "Approve this claim?")}
                  trigger={
                    <Button size="sm" variant="default">
                      {t("claim.approve", "Approve")}
                    </Button>
                  }
                />
              );
            }
            if (row.status === "paying") {
              actions.push(
                <Button
                  key="mark-paid"
                  onClick={() => openPaid(row)}
                  size="sm"
                  variant="default"
                >
                  {t("claim.markPaid", "Mark fulfilled")}
                </Button>
              );
            }
            if (row.status === "reviewing" || row.status === "paying") {
              actions.push(
                <Button
                  key="reject"
                  onClick={() => openReject(row)}
                  size="sm"
                  variant="destructive"
                >
                  {t("claim.reject", "Reject")}
                </Button>
              );
            }
            return actions;
          },
        }}
        columns={[
          { accessorKey: "id", header: "ID" },
          {
            accessorKey: "user",
            header: t("claim.user", "User"),
            cell: ({ row }) => (
              <div className="text-sm">
                <div>#{row.original.user.id}</div>
                {row.original.user.email && (
                  <div className="text-muted-foreground text-xs">
                    {row.original.user.email}
                  </div>
                )}
              </div>
            ),
          },
          {
            accessorKey: "prize",
            header: t("claim.prize", "Prize"),
            cell: ({ row }) => (
              <div className="text-sm">
                <div className="font-medium">{row.original.prize.name}</div>
                <Badge className="mt-0.5" variant="secondary">
                  {prizeTypeLabel(row.original.prize.type, t)}
                </Badge>
              </div>
            ),
          },
          {
            accessorKey: "claim_data",
            header: t("claim.claimData", "Claim info"),
            cell: ({ row }) => <ClaimDataCell data={row.original.claim_data} />,
          },
          {
            accessorKey: "status",
            header: t("claim.status", "Status"),
            cell: ({ row }) => {
              const meta = STATUS_META[row.original.status];
              return (
                <Badge className={meta?.className} variant="outline">
                  {meta
                    ? t(meta.labelKey, meta.labelDefault)
                    : row.original.status}
                </Badge>
              );
            },
          },
          {
            accessorKey: "fulfillment",
            header: t("claim.fulfillment", "Tx / Delivery"),
            cell: ({ row }) => (
              <div className="max-w-[180px] break-all text-xs">
                {row.original.tx_hash || row.original.delivery_ref || "--"}
                {row.original.reject_reason && (
                  <div className="text-rose-600">
                    {row.original.reject_reason}
                  </div>
                )}
              </div>
            ),
          },
          {
            accessorKey: "expires_at",
            header: t("claim.expiresAt", "Expires"),
            cell: ({ row }) =>
              row.original.expires_at
                ? formatDate(row.original.expires_at)
                : "--",
          },
          {
            accessorKey: "created_at",
            header: t("claim.createdAt", "Won at"),
            cell: ({ row }) =>
              row.original.created_at
                ? formatDate(row.original.created_at)
                : "--",
          },
        ]}
        header={{ title: t("claim.tableTitle", "Claims") }}
        params={[
          {
            key: "type",
            options: typeOptions,
            placeholder: t("claim.filterType", "Type"),
          },
          {
            key: "status",
            options: statusOptions,
            placeholder: t("claim.filterStatus", "Status"),
          },
          {
            key: "user_id",
            placeholder: t("claim.filterUserId", "User ID"),
          },
        ]}
        request={async (pagination, filter) => {
          const { data } = await getLotteryClaimList({
            page: pagination.page,
            size: pagination.size,
            activity_id: activity.id,
            type: (filter.type as API.LotteryPrizeType) || undefined,
            status: (filter.status as API.LotteryClaimStatus) || undefined,
            user_id: filter.user_id ? Number(filter.user_id) : undefined,
          });
          return {
            list: data.data?.claims || [],
            total: data.data?.total || 0,
          };
        }}
      />

      {/* Reject dialog */}
      <Dialog
        onOpenChange={(open) => {
          setRejectOpen(open);
          if (!open) {
            setCurrentRow(null);
            rejectForm.reset({ reason: "" });
          }
        }}
        open={rejectOpen}
      >
        <DialogContent>
          <DialogHeader>
            <DialogTitle>{t("claim.rejectTitle", "Reject claim")}</DialogTitle>
            <DialogDescription>
              {t(
                "claim.rejectDescription",
                "The reason is shown to the user, who may then resubmit."
              )}
            </DialogDescription>
          </DialogHeader>
          <Form {...rejectForm}>
            <form
              className="space-y-4"
              onSubmit={rejectForm.handleSubmit(async (values) => {
                if (!currentRow) return;
                await rejectMutation.mutateAsync({
                  id: currentRow.id,
                  reason: values.reason.trim(),
                });
              })}
            >
              <FormField
                control={rejectForm.control}
                name="reason"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>{t("claim.reason", "Reason")}</FormLabel>
                    <FormControl>
                      <Textarea
                        placeholder={t(
                          "claim.reasonPlaceholder",
                          "Reason shown to the user"
                        )}
                        rows={4}
                        {...field}
                      />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
              <DialogFooter>
                <Button
                  onClick={() => setRejectOpen(false)}
                  type="button"
                  variant="outline"
                >
                  {t("claim.cancel", "Cancel")}
                </Button>
                <Button disabled={rejectMutation.isPending} type="submit">
                  {t("claim.confirmReject", "Confirm reject")}
                </Button>
              </DialogFooter>
            </form>
          </Form>
        </DialogContent>
      </Dialog>

      {/* Mark-paid dialog */}
      <Dialog
        onOpenChange={(open) => {
          setPaidOpen(open);
          if (!open) {
            setCurrentRow(null);
            paidForm.reset({ tx_hash: "", delivery_ref: "" });
          }
        }}
        open={paidOpen}
      >
        <DialogContent>
          <DialogHeader>
            <DialogTitle>
              {t("claim.markPaidTitle", "Mark as fulfilled")}
            </DialogTitle>
            <DialogDescription>
              {t(
                "claim.markPaidDescription",
                "Crypto requires a tx hash; physical requires a delivery ref; manual requires at least one."
              )}
            </DialogDescription>
          </DialogHeader>
          <Form {...paidForm}>
            <form
              className="space-y-4"
              onSubmit={paidForm.handleSubmit(async (values) => {
                if (!currentRow) return;
                const txHash = values.tx_hash?.trim();
                const deliveryRef = values.delivery_ref?.trim();
                const prizeType = currentRow.prize.type;
                if (prizeType === "crypto" && !txHash) {
                  paidForm.setError("tx_hash", {
                    message: t(
                      "claim.txHashRequired",
                      "Tx hash is required for crypto"
                    ),
                  });
                  return;
                }
                if (prizeType === "physical" && !deliveryRef) {
                  paidForm.setError("delivery_ref", {
                    message: t(
                      "claim.deliveryRefRequired",
                      "Delivery ref is required for physical"
                    ),
                  });
                  return;
                }
                if (!(txHash || deliveryRef)) {
                  paidForm.setError("tx_hash", {
                    message: t(
                      "claim.oneRefRequired",
                      "Fill at least one field"
                    ),
                  });
                  return;
                }
                await paidMutation.mutateAsync({
                  id: currentRow.id,
                  tx_hash: txHash || undefined,
                  delivery_ref: deliveryRef || undefined,
                });
              })}
            >
              <FormField
                control={paidForm.control}
                name="tx_hash"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>{t("claim.txHash", "Tx hash")}</FormLabel>
                    <FormControl>
                      <Input placeholder="0x..." {...field} />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
              <FormField
                control={paidForm.control}
                name="delivery_ref"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>
                      {t("claim.deliveryRef", "Delivery ref")}
                    </FormLabel>
                    <FormControl>
                      <Input
                        placeholder={t(
                          "claim.deliveryRefPlaceholder",
                          "Tracking number"
                        )}
                        {...field}
                      />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
              <DialogFooter>
                <Button
                  onClick={() => setPaidOpen(false)}
                  type="button"
                  variant="outline"
                >
                  {t("claim.cancel", "Cancel")}
                </Button>
                <Button disabled={paidMutation.isPending} type="submit">
                  {t("claim.confirmMarkPaid", "Confirm")}
                </Button>
              </DialogFooter>
            </form>
          </Form>
        </DialogContent>
      </Dialog>
    </>
  );
}
