import type { NextRequest } from "next/server";
import { z } from "zod";
import { Prisma } from "@prisma/client";
import { prisma } from "@/lib/prisma";
import { rateLimit } from "@/lib/rate-limit";
import {
  getCurrentUser,
  getClientIp,
  getUserAgent,
} from "@/lib/current-user";
import { ok, ERR, sanitizeBigInt } from "@/lib/api-response";

type TxClient = Prisma.TransactionClient;

/**
 * 终身投票额度:每个用户共 12 票,每位艺人最多 1 票。
 * 用 const 而非读 DB,避免每次请求多一次查询。前端 store 同名常量保持一致。
 */
const TOTAL_VOTE_QUOTA = 12;

const VoteBody = z.object({
  artistId: z.string().min(1).max(8),
  // 旧前端仍可能传 count 字段(>=1),后端一律视为 1 票
  count: z.number().int().min(1).max(99_999).optional(),
});

/** 内部抛错用,事务捕获后转业务错误响应 */
class QuotaExhaustedError extends Error {
  constructor() {
    super("QUOTA_EXHAUSTED");
  }
}
class AlreadyVotedError extends Error {
  constructor() {
    super("ALREADY_VOTED");
  }
}

/**
 * POST /api/vote
 *
 * 新规则:
 *  - 每用户终身 12 票
 *  - 每艺人 1 票(DB 层 @@unique([userId, artistId]) 兜底)
 *  - 不可撤销,不限时
 *  - 单用户限流:1 秒 5 次;单 IP 限流:60 秒 60 次
 *
 * 流程:
 *  1. 鉴权 + 反作弊限流
 *  2. 校验活动开关(voteEnabled)
 *  3. 事务:已投艺人计数 >= 12 → QUOTA_EXHAUSTED;否则写票
 *     - DB unique 冲突 (P2002) → ALREADY_VOTED
 *  4. 累加 artist.voteCount;upsert FanSupport(votedTotal=1)
 *  5. 返回最新票数 + 剩余票数
 */
export async function POST(req: NextRequest) {
  try {
    const user = await getCurrentUser();
    if (!user) return ERR.UNAUTHORIZED();

    const userRl = await rateLimit(`vote:user:${user.id}`, 1, 5);
    if (!userRl.allowed) return ERR.RATE_LIMITED();

    const ip = await getClientIp();
    if (ip) {
      const ipRl = await rateLimit(`vote:ip:${ip}`, 60, 60);
      if (!ipRl.allowed) return ERR.RATE_LIMITED();
    }

    const raw = await req.json();
    const parsed = VoteBody.safeParse(raw);
    if (!parsed.success) {
      return ERR.VALIDATION(parsed.error.issues[0]?.message ?? "参数错误");
    }
    const { artistId } = parsed.data;

    const config = await prisma.activityConfig.findUnique({ where: { id: 1 } });
    if (!config?.voteEnabled) return ERR.ACTIVITY_OFF();
    // 新规则不限时,移除 startAt/endAt 校验

    const ua = await getUserAgent();

    try {
      const result = await prisma.$transaction(async (tx: TxClient) => {
        // 1. 终身额度校验:已投艺人数 >= 12 → 拒
        const votedSoFar = await tx.vote.count({ where: { userId: user.id } });
        if (votedSoFar >= TOTAL_VOTE_QUOTA) {
          throw new QuotaExhaustedError();
        }

        // 2. 写入投票
        //    DB unique (userId, artistId) 在 catch 里转 ALREADY_VOTED
        const vote = await tx.vote.create({
          data: {
            userId: user.id,
            artistId,
            count: 1,
            source: "QUOTA",
            ip: ip ?? undefined,
            ua: ua ?? undefined,
          },
        });

        // 3. 累加艺人票数
        const artist = await tx.artist.update({
          where: { id: artistId },
          data: { voteCount: { increment: 1 } },
          select: { id: true, voteCount: true, name: true },
        });

        // 4. 应援关系 —— 每艺人 1 票,votedTotal 固定 1
        await tx.fanSupport.upsert({
          where: { userId_artistId: { userId: user.id, artistId } },
          create: { userId: user.id, artistId, votedTotal: 1 },
          update: { votedTotal: 1 },
        });

        const votedAfter = votedSoFar + 1;
        return {
          vote,
          artist,
          votedCount: votedAfter,
          remaining: TOTAL_VOTE_QUOTA - votedAfter,
        };
      });

      return ok(
        sanitizeBigInt({
          artistId: result.artist.id,
          artistVotes: result.artist.voteCount,
          voteId: result.vote.id,
          votedCount: result.votedCount,
          remaining: result.remaining,
          totalQuota: TOTAL_VOTE_QUOTA,
        }),
      );
    } catch (e) {
      if (e instanceof QuotaExhaustedError) {
        return ERR.QUOTA_EXHAUSTED();
      }
      if (e instanceof AlreadyVotedError) {
        return ERR.ALREADY_VOTED();
      }
      // Prisma unique 冲突 → ALREADY_VOTED
      if (
        e instanceof Prisma.PrismaClientKnownRequestError &&
        e.code === "P2002"
      ) {
        return ERR.ALREADY_VOTED();
      }
      // 艺人不存在:
      // - P2003: FK 违反(vote.create 时 artistId 外键约束失败)
      // - P2025: 记录不存在(artist.update 找不到目标)
      if (
        e instanceof Prisma.PrismaClientKnownRequestError &&
        (e.code === "P2003" || e.code === "P2025")
      ) {
        return ERR.NOT_FOUND("艺人不存在");
      }
      throw e;
    }
  } catch (e) {
    console.error("[POST /api/vote]", e);
    return ERR.INTERNAL();
  }
}
