import { zodResolver } from "@hookform/resolvers/zod";
import { Button } from "@workspace/ui/components/button";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@workspace/ui/components/form";
import { ScrollArea } from "@workspace/ui/components/scroll-area";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@workspace/ui/components/select";
import {
  Sheet,
  SheetContent,
  SheetFooter,
  SheetHeader,
  SheetTitle,
} from "@workspace/ui/components/sheet";
import { Switch } from "@workspace/ui/components/switch";
import { ConfirmButton } from "@workspace/ui/composed/confirm-button";
import {
  EnhancedInput,
  type EnhancedInputProps,
} from "@workspace/ui/composed/enhanced-input";
import { Icon } from "@workspace/ui/composed/icon";
import {
  createLotteryPrize,
  deleteLotteryPrize,
  updateLotteryPrize,
} from "@workspace/ui/services/admin/lottery";
import { getSubscribeList } from "@workspace/ui/services/admin/subscribe";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";
import { z } from "zod";

// 概率单位约定：weight 1000 = 1%（支持 3 位小数概率，总权重 100000 = 100%）。
const WEIGHT_PER_PERCENT = 1000;

// numberOutput 把 text 输入转成数字（空/非法→undefined）。数字输入统一用 type="text"
// + 该 formatOutput，避开 EnhancedInput 在 type="number" 下 min/max 实时钳制导致的
// “输入 0 / 改中间位跳变”问题；提交仍是数字，后端收 int。
const numberOutput = (v: string | number): number | undefined => {
  const s = String(v ?? "").trim();
  if (s === "") {
    return;
  }
  const n = Number(s);
  return Number.isNaN(n) ? undefined : n;
};

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

const PRIZE_TYPE_OPTIONS: {
  value: API.LotteryPrizeType;
  labelKey: string;
  labelDefault: string;
}[] = [
  {
    value: "vpn_duration",
    labelKey: "prize.typeVpnDuration",
    labelDefault: "VPN Duration",
  },
  {
    value: "crypto",
    labelKey: "prize.typeCrypto",
    labelDefault: "Crypto",
  },
  {
    value: "none",
    labelKey: "prize.typeNone",
    labelDefault: "No Prize (Thanks)",
  },
];

const getPrizeSchema = (t: TranslateFn) =>
  z
    .object({
      type: z.enum(["vpn_duration", "crypto", "none"]),
      name: z.string().min(1, t("prize.nameRequired", "Name is required")),
      icon_url: z
        .string()
        .url(t("prize.iconUrlInvalid", "Must be a valid URL"))
        .or(z.literal(""))
        .optional(),
      weight: z
        .number()
        .min(0, t("prize.weightMin", "Probability must be at least 0"))
        .max(100, t("prize.weightMax", "Probability cannot exceed 100")),
      unlimited_stock: z.boolean(),
      total_stock: z.number().optional(),
      is_fallback: z.boolean(),
      duration_days: z.number().optional(),
      subscribe_id: z.number().optional(),
    })
    .superRefine((data, ctx) => {
      const issue = (path: string, message: string) => {
        ctx.addIssue({ code: z.ZodIssueCode.custom, message, path: [path] });
      };
      const isPositiveInt = (value?: number) =>
        !!value && value > 0 && Number.isInteger(value);
      if (data.type === "vpn_duration" && !isPositiveInt(data.duration_days)) {
        issue(
          "duration_days",
          t(
            "prize.durationDaysRequired",
            "Duration days must be a positive integer"
          )
        );
      }
      if (!(data.unlimited_stock || isPositiveInt(data.total_stock))) {
        issue(
          "total_stock",
          t(
            "prize.totalStockRequired",
            "Total stock must be a positive integer"
          )
        );
      }
    });

type PrizeFormValues = z.infer<ReturnType<typeof getPrizeSchema>>;

interface PrizeFormProps {
  activityId: number;
  slot: number;
  initialValues?: API.LotteryPrize;
  open: boolean;
  onOpenChange: (open: boolean) => void;
  onSuccess: () => void;
}

function toFormValues(prize?: API.LotteryPrize): PrizeFormValues {
  const config = prize?.config ?? {};
  return {
    type: (prize?.type as PrizeFormValues["type"]) ?? "vpn_duration",
    name: prize?.name ?? "",
    icon_url: prize?.icon_url ?? "",
    weight: (prize?.weight ?? 0) / WEIGHT_PER_PERCENT,
    unlimited_stock: prize ? prize.total_stock === null : true,
    total_stock: prize?.total_stock ?? undefined,
    is_fallback: prize?.is_fallback ?? false,
    duration_days: config.duration_days as number | undefined,
    subscribe_id: config.subscribe_id as number | undefined,
  };
}

function toConfig(values: PrizeFormValues): Record<string, any> {
  if (values.type === "vpn_duration") {
    const config: Record<string, any> = { duration_days: values.duration_days };
    // 可选：无活跃订阅时按该套餐新建订阅发放时长。0/未选则沿用旧行为（跳过发放）。
    if (values.subscribe_id && values.subscribe_id > 0) {
      config.subscribe_id = values.subscribe_id;
    }
    return config;
  }
  // crypto(人工发放) / none 无需额外配置：中奖后凭截图联系客服线下发放。
  return {};
}

export default function PrizeForm({
  activityId,
  slot,
  initialValues,
  open,
  onOpenChange,
  onSuccess,
}: PrizeFormProps) {
  const { t } = useTranslation("lottery");
  const [loading, setLoading] = useState(false);
  const [plans, setPlans] = useState<API.SubscribeItem[]>([]);
  const form = useForm<PrizeFormValues>({
    resolver: zodResolver(getPrizeSchema(t)),
    defaultValues: toFormValues(initialValues),
  });
  const type = form.watch("type");
  const unlimitedStock = form.watch("unlimited_stock");
  const isFallback = form.watch("is_fallback");
  const isEdit = !!initialValues?.id;
  const targetSlot = initialValues?.slot ?? slot;

  useEffect(() => {
    if (open) form.reset(toFormValues(initialValues));
  }, [form, initialValues, open]);

  // vpn_duration 需要一个可选的“新建订阅套餐”下拉，仅在面板打开且类型匹配时拉取。
  useEffect(() => {
    if (!(open && type === "vpn_duration") || plans.length > 0) return;
    getSubscribeList({ page: 1, size: 100 })
      .then(({ data }) => setPlans(data?.data?.list ?? []))
      .catch(() => {
        // Request layer already surfaces the error toast
      });
  }, [open, type, plans.length]);

  async function handleSubmit(values: PrizeFormValues) {
    setLoading(true);
    try {
      const body: API.CreateLotteryPrizeRequest = {
        activity_id: activityId,
        slot: targetSlot,
        type: values.type,
        name: values.name.trim(),
        icon_url: values.icon_url?.trim() ?? "",
        config: toConfig(values),
        weight: values.is_fallback
          ? 0
          : Math.round(values.weight * WEIGHT_PER_PERCENT),
        total_stock: values.unlimited_stock
          ? null
          : (values.total_stock ?? null),
        is_fallback: values.is_fallback,
      };
      if (isEdit) {
        await updateLotteryPrize({ ...body, id: initialValues!.id });
        toast.success(t("prize.updateSuccess", "Prize updated"));
      } else {
        await createLotteryPrize(body);
        toast.success(t("prize.createSuccess", "Prize created"));
      }
      onSuccess();
      onOpenChange(false);
    } catch {
      // Request layer already surfaces the error toast
    } finally {
      setLoading(false);
    }
  }

  async function handleDelete() {
    if (!initialValues?.id) return;
    setLoading(true);
    try {
      await deleteLotteryPrize({ id: initialValues.id });
      toast.success(t("prize.deleteSuccess", "Prize deleted"));
      onSuccess();
      onOpenChange(false);
    } catch {
      // Request layer already surfaces the error toast
    } finally {
      setLoading(false);
    }
  }

  const renderInput = (
    name: "name" | "icon_url" | "weight" | "total_stock" | "duration_days",
    label: string,
    inputProps: Partial<EnhancedInputProps<any>>,
    description?: string
  ) => (
    <FormField
      control={form.control}
      name={name}
      render={({ field }) => (
        <FormItem>
          <FormLabel>{label}</FormLabel>
          <FormControl>
            <EnhancedInput
              onValueChange={(value) => form.setValue(name, value)}
              value={field.value}
              {...inputProps}
            />
          </FormControl>
          {description && (
            <p className="text-muted-foreground text-xs">{description}</p>
          )}
          <FormMessage />
        </FormItem>
      )}
    />
  );

  const renderSwitch = (
    name: "unlimited_stock" | "is_fallback",
    label: string,
    description?: string
  ) => (
    <FormField
      control={form.control}
      name={name}
      render={({ field }) => (
        <FormItem className="flex items-center justify-between rounded-md border p-3">
          <div className="space-y-1">
            <FormLabel>{label}</FormLabel>
            {description && (
              <p className="text-muted-foreground text-xs">{description}</p>
            )}
          </div>
          <FormControl>
            <Switch
              checked={field.value}
              onCheckedChange={(checked) => form.setValue(name, checked)}
            />
          </FormControl>
        </FormItem>
      )}
    />
  );

  return (
    <Sheet onOpenChange={onOpenChange} open={open}>
      <SheetContent className="w-[520px] max-w-full md:max-w-screen-md">
        <SheetHeader>
          <SheetTitle>
            {isEdit
              ? t("prize.editTitle", "Edit Prize")
              : t("prize.createTitle", "Add Prize")}
            {" · "}
            {t("prize.slotLabel", "Slot")} {targetSlot}
          </SheetTitle>
        </SheetHeader>
        <ScrollArea className="h-[calc(100vh-48px-36px-36px-env(safe-area-inset-top))]">
          <Form {...form}>
            <form
              className="space-y-4 px-6 pt-4"
              onSubmit={form.handleSubmit(handleSubmit)}
            >
              <FormField
                control={form.control}
                name="type"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>{t("prize.type", "Prize Type")}</FormLabel>
                    <FormControl>
                      <Select
                        onValueChange={(value) =>
                          form.setValue(
                            field.name,
                            value as PrizeFormValues["type"]
                          )
                        }
                        value={field.value}
                      >
                        <SelectTrigger className="w-full">
                          <SelectValue
                            placeholder={t("prize.selectType", "Select type")}
                          />
                        </SelectTrigger>
                        <SelectContent>
                          {PRIZE_TYPE_OPTIONS.map((option) => (
                            <SelectItem key={option.value} value={option.value}>
                              {t(option.labelKey, option.labelDefault)}
                            </SelectItem>
                          ))}
                        </SelectContent>
                      </Select>
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
              {renderInput("name", t("prize.name", "Prize Name"), {
                placeholder: t("prize.namePlaceholder", "e.g. 1-Day Pass"),
              })}
              {renderInput("icon_url", t("prize.iconUrl", "Icon URL"), {
                placeholder: "https://",
              })}
              {type === "vpn_duration" &&
                renderInput(
                  "duration_days",
                  t("prize.durationDays", "Duration (days)"),
                  {
                    type: "text",
                    inputMode: "numeric",
                    formatOutput: numberOutput,
                    placeholder: t("prize.durationDaysPlaceholder", "e.g. 1"),
                    suffix: t("prize.daysSuffix", "days"),
                  }
                )}
              {type === "vpn_duration" && (
                <FormField
                  control={form.control}
                  name="subscribe_id"
                  render={({ field }) => (
                    <FormItem>
                      <FormLabel>
                        {t("prize.subscribePlan", "New-subscription plan")}
                      </FormLabel>
                      <FormControl>
                        <Select
                          onValueChange={(value) =>
                            form.setValue(
                              "subscribe_id",
                              value ? Number(value) : undefined
                            )
                          }
                          value={field.value ? String(field.value) : undefined}
                        >
                          <SelectTrigger className="w-full">
                            <SelectValue
                              placeholder={t(
                                "prize.subscribePlanPlaceholder",
                                "None — skip if user has no active subscription"
                              )}
                            />
                          </SelectTrigger>
                          <SelectContent>
                            {plans.map((plan) => (
                              <SelectItem key={plan.id} value={String(plan.id)}>
                                {plan.name ?? `#${plan.id}`}
                              </SelectItem>
                            ))}
                          </SelectContent>
                        </Select>
                      </FormControl>
                      <p className="text-muted-foreground text-xs">
                        {t(
                          "prize.subscribePlanHint",
                          "When the user has no active subscription, create one on this plan and grant the duration. Leave empty to skip granting."
                        )}
                      </p>
                      <FormMessage />
                    </FormItem>
                  )}
                />
              )}
              {type === "none" && (
                <p className="rounded-md bg-muted/50 p-3 text-muted-foreground text-xs">
                  {t(
                    "prize.noneHint",
                    "No config needed. Consider enabling fallback so users always land on this prize when limited prizes run out."
                  )}
                </p>
              )}
              {type === "crypto" && (
                <p className="rounded-md bg-muted/50 p-3 text-muted-foreground text-xs">
                  {t(
                    "prize.manualPrizeHint",
                    "Manual prize: no extra config. When won, the user contacts customer service with a screenshot to redeem — no in-app claim form."
                  )}
                </p>
              )}
              {renderInput(
                "weight",
                t("prize.weight", "Win probability (%)"),
                {
                  type: "text",
                  inputMode: "decimal",
                  formatOutput: numberOutput,
                  suffix: "%",
                  disabled: isFallback,
                },
                isFallback
                  ? t(
                      "prize.fallbackIgnoresWeight",
                      "Fallback prize ignores probability (never randomly drawn)"
                    )
                  : t(
                      "prize.weightHint",
                      "Percent chance in the grid. All drawable prizes must total 100%. 0 = shown but never drawn."
                    )
              )}
              {renderSwitch(
                "unlimited_stock",
                t("prize.unlimitedStock", "Unlimited Stock")
              )}
              {!unlimitedStock &&
                renderInput(
                  "total_stock",
                  t("prize.totalStock", "Total Stock"),
                  {
                    type: "text",
                    inputMode: "numeric",
                    formatOutput: numberOutput,
                    placeholder: t("prize.totalStockPlaceholder", "e.g. 100"),
                  }
                )}
              {renderSwitch(
                "is_fallback",
                t("prize.isFallback", "Fallback Prize"),
                t(
                  "prize.isFallbackHint",
                  "Awarded when limited prizes are sold out"
                )
              )}
            </form>
          </Form>
        </ScrollArea>
        <SheetFooter className="flex-row justify-end gap-2 pt-3">
          {isEdit && (
            <ConfirmButton
              cancelText={t("prize.cancel", "Cancel")}
              confirmText={t("prize.confirmDelete", "Delete")}
              description={t(
                "prize.deleteDescription",
                "This prize will be removed from the grid. This action cannot be undone."
              )}
              onConfirm={handleDelete}
              title={t("prize.deleteTitle", "Delete this prize?")}
              trigger={
                <Button
                  className="mr-auto"
                  disabled={loading}
                  variant="destructive"
                >
                  {t("prize.delete", "Delete")}
                </Button>
              }
            />
          )}
          <Button
            disabled={loading}
            onClick={() => onOpenChange(false)}
            variant="outline"
          >
            {t("prize.cancel", "Cancel")}
          </Button>
          <Button disabled={loading} onClick={form.handleSubmit(handleSubmit)}>
            {loading && (
              <Icon className="mr-2 animate-spin" icon="mdi:loading" />
            )}
            {t("prize.confirm", "Confirm")}
          </Button>
        </SheetFooter>
      </SheetContent>
    </Sheet>
  );
}
