import {
  Alert,
  AlertDescription,
  AlertTitle,
} from "@workspace/ui/components/alert";
import { Badge } from "@workspace/ui/components/badge";
import { Skeleton } from "@workspace/ui/components/skeleton";
import { cn } from "@workspace/ui/lib/utils";
import { getLotteryPrizeList } from "@workspace/ui/services/admin/lottery";
import { AlertTriangle, Plus } from "lucide-react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import PrizeForm from "./prize-form";

const DEFAULT_GRID_SIZE = 9;
const CENTER_SLOT = 4;
const CENTS_PER_YUAN = 100;
// 概率单位约定：weight 1000 = 1%，总权重 100000 = 100.000%（支持 3 位小数概率）。
const WEIGHT_PER_PERCENT = 1000;
const FULL_TOTAL_WEIGHT = 100 * WEIGHT_PER_PERCENT;

// weightToPercent 把原始 weight 转成百分比字符串（最多 3 位小数，去尾零）。
function weightToPercent(weight: number): string {
  const pct = weight / WEIGHT_PER_PERCENT;
  return `${Number.parseFloat(pct.toFixed(3))}`;
}

interface PrizeGridProps {
  activity: API.LotteryActivity;
}

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

function prizeTypeLabel(type: API.LotteryPrizeType, t: TranslateFn): string {
  const labels: Record<string, string> = {
    vpn_duration: t("prize.typeVpnDuration", "VPN Duration"),
    commission: t("prize.typeCommission", "Commission"),
    none: t("prize.typeNone", "No Prize (Thanks)"),
    crypto: t("prize.typeCrypto", "Crypto"),
    physical: t("prize.typePhysical", "Physical"),
    manual_other: t("prize.typeManualOther", "Manual (Other)"),
    coupon: t("prize.typeCoupon", "Coupon"),
    points: t("prize.typePoints", "Points"),
  };
  return labels[type] ?? type;
}

// prizeConfigSummary 把奖品的类型专属 config 渲染成一行可读文本，
// 让九宫格卡片显示真实配置值（免费时长天数 / 佣金金额），而不是只有类型徽章。
function prizeConfigSummary(
  prize: API.LotteryPrize,
  t: TranslateFn
): string | null {
  const config = prize.config ?? {};
  if (prize.type === "vpn_duration") {
    const days = config.duration_days as number | undefined;
    if (typeof days === "number" && days > 0) {
      return `${days} ${t("prize.daysSuffix", "days")}`;
    }
    return null;
  }
  if (prize.type === "commission") {
    const cents = config.amount_cents as number | undefined;
    if (typeof cents === "number" && cents > 0) {
      return `¥${(cents / CENTS_PER_YUAN).toFixed(2)}`;
    }
    return null;
  }
  return null;
}

interface FormState {
  open: boolean;
  slot: number;
  prize?: API.LotteryPrize;
}

export default function PrizeGrid({ activity }: PrizeGridProps) {
  const { t } = useTranslation("lottery");
  const [prizes, setPrizes] = useState<API.LotteryPrize[]>([]);
  const [loading, setLoading] = useState(false);
  const [formState, setFormState] = useState<FormState>({
    open: false,
    slot: 0,
  });

  const fetchPrizes = useCallback(async () => {
    setLoading(true);
    try {
      const { data } = await getLotteryPrizeList({ activity_id: activity.id });
      setPrizes(data?.data?.list ?? []);
    } catch {
      // Request layer already surfaces the error toast
    } finally {
      setLoading(false);
    }
  }, [activity.id]);

  useEffect(() => {
    fetchPrizes();
  }, [fetchPrizes]);

  const prizeBySlot = useMemo(() => {
    const map = new Map<number, API.LotteryPrize>();
    for (const prize of prizes) {
      map.set(prize.slot, prize);
    }
    return map;
  }, [prizes]);

  const randomPrizes = useMemo(
    () => prizes.filter((prize) => prize.weight > 0 && !prize.is_fallback),
    [prizes]
  );
  const totalWeight = useMemo(
    () => randomPrizes.reduce((sum, prize) => sum + prize.weight, 0),
    [randomPrizes]
  );
  const hasFallback = prizes.some((prize) => prize.is_fallback);
  const totalIsValid = totalWeight === FULL_TOTAL_WEIGHT;
  const gridSize = activity.grid_size || DEFAULT_GRID_SIZE;
  const slots = Array.from({ length: gridSize }, (_, index) => index);

  const openForm = (slot: number, prize?: API.LotteryPrize) => {
    setFormState({ open: true, slot, prize });
  };

  if (loading && prizes.length === 0) {
    return (
      <div className="grid grid-cols-3 gap-3">
        {slots.map((slot) => (
          <Skeleton className="min-h-[132px] rounded-lg" key={slot} />
        ))}
      </div>
    );
  }

  return (
    <div className="space-y-4">
      <div className="rounded-lg border bg-muted/30 p-3">
        <div className="mb-2 flex items-center justify-between">
          <p className="font-medium text-sm">
            {t("prize.probabilityPreview", "Probability Preview")}
          </p>
          {randomPrizes.length > 0 && (
            <Badge variant={totalIsValid ? "secondary" : "destructive"}>
              {t("prize.probabilityTotal", "Total")}:{" "}
              {weightToPercent(totalWeight)}%
            </Badge>
          )}
        </div>
        {randomPrizes.length > 0 ? (
          <div className="flex flex-wrap gap-2">
            {randomPrizes.map((prize) => (
              <Badge key={prize.id} variant="secondary">
                {prize.name}: {weightToPercent(prize.weight)}%
              </Badge>
            ))}
          </div>
        ) : (
          <p className="text-muted-foreground text-xs">
            {t(
              "prize.noRandomPrizes",
              "No prizes participate in the random draw yet"
            )}
          </p>
        )}
      </div>
      {randomPrizes.length > 0 && !totalIsValid && (
        <Alert variant="destructive">
          <AlertTriangle className="h-4 w-4" />
          <AlertTitle>
            {t("prize.totalNot100Title", "Probabilities must total 100%")}
          </AlertTitle>
          <AlertDescription>
            {t(
              "prize.totalNot100Hint",
              "The drawable prizes currently total {{total}}%. Adjust each prize's win probability so they sum to exactly 100%.",
              { total: weightToPercent(totalWeight) }
            )}
          </AlertDescription>
        </Alert>
      )}
      {!hasFallback && (
        <Alert>
          <AlertTriangle className="h-4 w-4" />
          <AlertTitle>
            {t("prize.noFallbackTitle", "No fallback prize")}
          </AlertTitle>
          <AlertDescription>
            {t(
              "prize.noFallbackHint",
              "Consider configuring a fallback prize so draws never fail when limited prizes run out."
            )}
          </AlertDescription>
        </Alert>
      )}
      <div className="grid grid-cols-3 gap-3">
        {slots.map((slot) => {
          const prize = prizeBySlot.get(slot);
          return (
            <button
              className={cn(
                "relative flex min-h-[132px] flex-col items-center justify-center gap-1 rounded-lg border p-3 text-center transition-colors hover:border-primary",
                prize ? "bg-card" : "border-dashed text-muted-foreground"
              )}
              key={slot}
              onClick={() => openForm(slot, prize)}
              type="button"
            >
              <span className="absolute top-1 left-1.5 text-[10px] text-muted-foreground">
                #{slot}
              </span>
              {slot === CENTER_SLOT && (
                <Badge
                  className="absolute top-1 right-1 px-1.5 text-[10px]"
                  variant="outline"
                >
                  {t("prize.centerSlotHint", "Usually the draw button")}
                </Badge>
              )}
              {prize ? (
                <>
                  {prize.icon_url ? (
                    <img
                      alt={prize.name}
                      className="h-8 w-8 rounded object-cover"
                      height={32}
                      src={prize.icon_url}
                      width={32}
                    />
                  ) : (
                    <span aria-hidden className="text-2xl">
                      🎁
                    </span>
                  )}
                  <span className="line-clamp-1 font-medium text-sm">
                    {prize.name}
                  </span>
                  <Badge variant="secondary">
                    {prizeTypeLabel(prize.type, t)}
                  </Badge>
                  {(() => {
                    const summary = prizeConfigSummary(prize, t);
                    return summary ? (
                      <span className="line-clamp-1 font-medium text-primary text-xs">
                        {summary}
                      </span>
                    ) : null;
                  })()}
                  <span className="text-muted-foreground text-xs">
                    {t("prize.weightShort", "Prob")}:{" "}
                    {prize.is_fallback
                      ? "—"
                      : `${weightToPercent(prize.weight)}%`}{" "}
                    · {t("prize.stockShort", "Stock")}:{" "}
                    {prize.total_stock === null ? "∞" : prize.total_stock}
                  </span>
                  <div className="flex flex-wrap justify-center gap-1">
                    {prize.is_fallback && (
                      <Badge variant="outline">
                        {t("prize.fallbackBadge", "Fallback")}
                      </Badge>
                    )}
                    {prize.sold_out && (
                      <Badge variant="destructive">
                        {t("prize.soldOutBadge", "Sold Out")}
                      </Badge>
                    )}
                  </div>
                </>
              ) : (
                <>
                  <Plus className="h-5 w-5" />
                  <span className="text-xs">
                    {t("prize.addPrize", "Add Prize")}
                  </span>
                </>
              )}
            </button>
          );
        })}
      </div>
      <PrizeForm
        activityId={activity.id}
        initialValues={formState.prize}
        onOpenChange={(open) => setFormState((prev) => ({ ...prev, open }))}
        onSuccess={fetchPrizes}
        open={formState.open}
        slot={formState.slot}
      />
    </div>
  );
}
