import { prisma } from '../../models';
import { MemberLevel } from '../../types';

// ============================================
// TTS服务商成本配置（2026-05-20 更新：修正为阿里百炼官方定价）
// 原配置存在单位错误（千→应为百万/万），已全部修正
// ============================================
export const TTS_COST_CONFIG = {
  // TTS服务商配置（成本：¥/万字符，基于阿里百炼官方定价）
  providers: {
    // 免费方案
    iflytek_free: {
      name: '科大讯飞-基础版',
      costPer10kChars: 0,  // 免费
      quality: 'standard',
      voiceOptions: 10,
      freeQuota: 100000,
      novelRating: 3
    },
    // 阿里百炼 CosyVoice 标准版（默认，¥1/万字符）
    aliyun_cosyvoice: {
      name: '阿里百炼 cosyvoice-v3-flash',
      costPer10kChars: 1.0,  // ¥1/万字符（阿里官方定价）
      quality: 'standard',
      voiceOptions: 25,
      freeQuota: 10000,  // 1万字符免费/90天
      novelRating: 4
    },
    // 阿里百炼 CosyVoice Plus（高质量）
    aliyun_cosyvoice_plus: {
      name: '阿里百炼 cosyvoice-v3-plus',
      costPer10kChars: 2.0,  // ¥2/万字符
      quality: 'high',
      voiceOptions: 40,
      freeQuota: 10000,
      novelRating: 5
    },
    // 阿里百炼 TTS Flash（备选）
    aliyun_tts_flash: {
      name: '阿里百炼 qwen3-tts-instruct-flash',
      costPer10kChars: 0.8,  // ¥0.8/万字符
      quality: 'standard',
      voiceOptions: 30,
      freeQuota: 10000,
      novelRating: 4
    }
  },
  
  // AI模型成本配置（¥/百万token，基于阿里百炼官方定价）
  aiModels: {
    qwen_plus: {
      name: '通义千问 Qwen-Plus',
      inputCostPerMToken: 0.8,   // ¥0.8/百万token（阿里官方）
      outputCostPerMToken: 2.0,  // ¥2.0/百万token（阿里官方，非思考模式）
      quality: 'standard',
      default: true
    },
    qwen3_flash: {
      name: '通义千问 Qwen3.5-Flash',
      inputCostPerMToken: 0.2,   // ¥0.2/百万token
      outputCostPerMToken: 2.0,  // ¥2.0/百万token
      quality: 'standard'
    },
    qwen3_plus: {
      name: '通义千问 Qwen3.6-Plus',
      inputCostPerMToken: 2.0,   // ¥2/百万token
      outputCostPerMToken: 12.0, // ¥12/百万token
      quality: 'high'
    },
    deepseek_v3: {
      name: 'DeepSeek V3.2（阿里百炼）',
      inputCostPerMToken: 2.0,   // ¥2/百万token
      outputCostPerMToken: 3.0,  // ¥3/百万token
      quality: 'standard'
    }
  },
  
  // 各等级默认TTS方案
  planTTSProvider: {
    0: 'iflytek_free',           // 免费版：科大讯飞免费
    1: 'aliyun_cosyvoice',       // 入门版：CosyVoice标准版
    2: 'aliyun_cosyvoice',       // 专业版：CosyVoice标准版
    3: 'aliyun_cosyvoice_plus'   // 旗舰版：CosyVoice Plus
  },
  
  // 默认AI模型
  defaultAIModel: 'qwen_plus'
};

// ============================================
// 定价系数（可运营调整）
// ============================================
export const PRICING_COEFFICIENT = 2.0;  // 售价 = API成本 × 系数

// ============================================
// Token成本配置（AI生成成本 + TTS成本）
// 2026-05-20 修正：基于阿里百炼官方定价，单位修正为百万token/万字符
// ============================================
export const TOKEN_COST_CONFIG = {
  // 基础成本（qwen-plus AI + cosyvoice-v3-flash TTS）
  // AI: 1.5万token/万字符 × ¥2/百万token输出 + ¥0.8/百万token输入 = ¥0.042/万字符
  // TTS: cosyvoice-v3-flash ¥1/万字符
  // 合计: ¥1.042/万字符
  baseCostPer10kChars: 1.042,
  
  // AI模型（¥/百万token，阿里百炼官方定价）
  models: {
    qwen_plus: {
      name: '通义千问 Qwen-Plus',
      inputCostPerMToken: 0.8,    // ¥0.8/百万token（非思考模式）
      outputCostPerMToken: 2.0,   // ¥2.0/百万token
      quality: 'standard',
      default: true
    },
    qwen3_flash: {
      name: '通义千问 Qwen3.5-Flash',
      inputCostPerMToken: 0.2,    // ¥0.2/百万token
      outputCostPerMToken: 2.0,   // ¥2.0/百万token
      quality: 'standard'
    },
    qwen3_plus: {
      name: '通义千问 Qwen3.6-Plus',
      inputCostPerMToken: 2.0,    // ¥2/百万token
      outputCostPerMToken: 12.0,  // ¥12/百万token
      quality: 'high'
    },
    deepseek_v3: {
      name: 'DeepSeek V3.2（阿里百炼）',
      inputCostPerMToken: 2.0,    // ¥2/百万token
      outputCostPerMToken: 3.0,   // ¥3/百万token
      quality: 'standard'
    }
  },
  
  // TTS成本（¥/万字符）
  ttsModels: {
    cosyvoice: {
      name: 'cosyvoice-v3-flash（标准版）',
      costPer10kChars: 1.0       // ¥1/万字符
    },
    cosyvoice_plus: {
      name: 'cosyvoice-v3-plus',
      costPer10kChars: 2.0       // ¥2/万字符
    },
    qwen3_tts_flash: {
      name: 'qwen3-tts-instruct-flash',
      costPer10kChars: 0.8       // ¥0.8/万字符
    }
  }
};

// 计算Token生成成本（基于阿里百炼实际定价）
export function calculateTokenCost(
  textLength: number, 
  aiModel: string = 'qwen_plus',
  ttsModel: string = 'cosyvoice'
): {
  aiInputCost: number;
  aiOutputCost: number;
  ttsCost: number;
  totalCost: number;
  suggestedPrice: number;
} {
  const modelConfig = TOKEN_COST_CONFIG.models[aiModel] || TOKEN_COST_CONFIG.models.qwen_plus;
  const ttsConfig = TOKEN_COST_CONFIG.ttsModels[ttsModel] || TOKEN_COST_CONFIG.ttsModels.cosyvoice;
  
  // 估算token数：中文1字≈1.5token
  const estimatedTokens = textLength * 1.5;
  
  // AI输入成本（prompt约占输出的10%）
  const aiInputCost = (estimatedTokens * 0.1 / 1_000_000) * modelConfig.inputCostPerMToken;
  
  // AI输出成本
  const aiOutputCost = (estimatedTokens / 1_000_000) * modelConfig.outputCostPerMToken;
  
  // TTS合成成本
  const ttsCost = (textLength / 10_000) * ttsConfig.costPer10kChars;
  
  // 总API成本
  const totalCost = aiInputCost + aiOutputCost + ttsCost;
  
  // 建议售价 = 成本 × 定价系数
  const suggestedPrice = totalCost * PRICING_COEFFICIENT;
  
  return {
    aiInputCost: Math.round(aiInputCost * 10000) / 10000,
    aiOutputCost: Math.round(aiOutputCost * 10000) / 10000,
    ttsCost: Math.round(ttsCost * 10000) / 10000,
    totalCost: Math.round(totalCost * 10000) / 10000,
    suggestedPrice: Math.round(suggestedPrice * 100) / 100
  };
}

// 默认套餐配置（基于阿里百炼实际成本 × PRICING_COEFFICIENT）
// 定价公式: priceMonthly = monthlyMinutes × AUDIO_BILLING_CONFIG.pricing.monthly
// 成本: cosyvoice-v3-flash ¥1/万字符 + qwen-plus AI = ¥0.016/分钟, 系数: 2, 售价: ¥0.032/分钟
// ⚠️ 实际按量计费，套餐只是包装展示
export const DEFAULT_PLANS = [
  {
    name: '免费版',
    level: 0,
    priceMonthly: 0,
    priceYearly: 0,
    description: '适合轻度体验',
    features: JSON.stringify([
      '每月100分钟音频',
      '基础音色5种',
      '标准音质'
    ]),
    isRecommended: false,
    sortOrder: 0,
    dailyGenerations: 3,
    perGenerationLimit: 10000,
    monthlyTokens: 15000,
    monthlyMinutes: 100,
    yearlyTokens: null,
    voiceOptions: 5,
    audioQuality: 'standard',
    apiAccess: false,
    batchProcessing: false,
    teamManagement: false,
    overageEnabled: false,
    overagePrice: 0
  },
  {
    name: '入门版',
    level: 1,
    priceMonthly: 10,
    priceYearly: 100,
    description: '适合轻度使用',
    features: JSON.stringify([
      '每月300分钟音频',
      '全部音色',
      '高清音质',
      '超出¥0.048/分钟'
    ]),
    isRecommended: false,
    sortOrder: 1,
    dailyGenerations: 10,
    perGenerationLimit: 10000,
    monthlyTokens: 45000,
    monthlyMinutes: 300,
    yearlyTokens: null,
    voiceOptions: -1,
    audioQuality: 'high',
    apiAccess: false,
    batchProcessing: false,
    teamManagement: false,
    overageEnabled: true,
    overagePrice: 0.048
  },
  {
    name: '专业版',
    level: 2,
    priceMonthly: 32,
    priceYearly: 320,
    description: '适合内容创作者 ⭐推荐',
    features: JSON.stringify([
      '每月1000分钟音频',
      '全部音色+定制音色',
      '高清音质',
      '超出¥0.042/分钟'
    ]),
    isRecommended: true,
    sortOrder: 2,
    dailyGenerations: -1,
    perGenerationLimit: 10000,
    monthlyTokens: 150000,
    monthlyMinutes: 1000,
    yearlyTokens: null,
    voiceOptions: -1,
    audioQuality: 'high',
    apiAccess: false,
    batchProcessing: false,
    teamManagement: false,
    overageEnabled: true,
    overagePrice: 0.042
  },
  {
    name: '旗舰版',
    level: 3,
    priceMonthly: 128,
    priceYearly: 1280,
    description: '适合重度使用',
    features: JSON.stringify([
      '每月4000分钟音频',
      '全部音色+定制音色',
      '高清音质',
      'VIP优先队列',
      '超出¥0.036/分钟'
    ]),
    isRecommended: false,
    sortOrder: 3,
    dailyGenerations: -1,
    perGenerationLimit: 10000,
    monthlyTokens: 600000,
    monthlyMinutes: 4000,
    yearlyTokens: null,
    voiceOptions: -1,
    audioQuality: 'high',
    apiAccess: true,
    batchProcessing: false,
    teamManagement: false,
    overageEnabled: true,
    overagePrice: 0.036
  },
  {
    name: '企业版',
    level: 4,
    priceMonthly: 480,
    priceYearly: 4800,
    description: '适合企业用户',
    features: JSON.stringify([
      '每月15000分钟音频',
      '全部功能',
      '专属技术支持',
      '批量处理',
      '团队管理',
      '超出¥0.032/分钟'
    ]),
    isRecommended: false,
    sortOrder: 4,
    dailyGenerations: -1,
    perGenerationLimit: 10000,
    monthlyTokens: 2250000,
    monthlyMinutes: 15000,
    yearlyTokens: null,
    voiceOptions: -1,
    audioQuality: 'high',
    apiAccess: true,
    batchProcessing: true,
    teamManagement: true,
    overageEnabled: true,
    overagePrice: 0.032
  }
];

// 初始化套餐数据
export async function initializePlans() {
  const existingPlans = await prisma.subscriptionPlan.count();
  
  if (existingPlans === 0) {
    console.log('初始化订阅套餐数据...');
    for (const plan of DEFAULT_PLANS) {
      await prisma.subscriptionPlan.create({ data: plan });
    }
    console.log('订阅套餐初始化完成');
  }
}

// 获取所有套餐列表
export async function getPlans() {
  const plans = await prisma.subscriptionPlan.findMany({
    where: { isActive: true },
    orderBy: { sortOrder: 'asc' }
  });

  return plans.map(plan => ({
    ...plan,
    priceMonthly: Number(plan.priceMonthly),
    priceYearly: Number(plan.priceYearly),
    features: JSON.parse(plan.features || '[]')
  }));
}

// 获取单个套餐详情
export async function getPlanById(planId: number) {
  const plan = await prisma.subscriptionPlan.findUnique({
    where: { id: planId }
  });

  if (!plan) {
    throw new Error('套餐不存在');
  }

  return {
    ...plan,
    priceMonthly: Number(plan.priceMonthly),
    priceYearly: Number(plan.priceYearly),
    features: JSON.parse(plan.features || '[]')
  };
}

// 获取用户当前订阅信息
export async function getUserSubscription(userId: number) {
  const subscription = await prisma.subscription.findFirst({
    where: {
      userId,
      status: 'active',
      endDate: { gt: new Date() }
    },
    include: {
      plan: true
    },
    orderBy: { endDate: 'desc' }
  });

  return subscription;
}

// 获取用户Token余额
export async function getUserTokenBalance(userId: number) {
  let balance = await prisma.tokenBalance.findUnique({
    where: { userId }
  });

  if (!balance) {
    // 初始化Token余额
    balance = await prisma.tokenBalance.create({
      data: {
        userId,
        totalTokens: 10000, // 默认免费额度
        usedTokens: 0
      }
    });
  }

  const remaining = balance.totalTokens - balance.usedTokens;

  return {
    totalTokens: balance.totalTokens,
    usedTokens: balance.usedTokens,
    remainingTokens: remaining,
    resetDate: balance.resetDate,
    isUnlimited: balance.totalTokens === -1
  };
}

// 获取Token使用记录
export async function getTokenUsageList(userId: number, page: number = 1, pageSize: number = 20) {
  const where = { userId };
  const total = await prisma.tokenUsage.count({ where });
  
  const list = await prisma.tokenUsage.findMany({
    where,
    orderBy: { createdAt: 'desc' },
    skip: (page - 1) * pageSize,
    take: pageSize
  });

  return {
    list,
    total,
    page,
    pageSize,
    totalPages: Math.ceil(total / pageSize)
  };
}

// 消耗Token
export async function consumeToken(
  userId: number,
  amount: number,
  type: string,
  contentLength: number,
  description?: string
) {
  const balance = await prisma.tokenBalance.findUnique({
    where: { userId }
  });

  if (!balance) {
    throw new Error('用户Token余额不存在');
  }

  if (balance.totalTokens !== -1 && balance.usedTokens + amount > balance.totalTokens) {
    throw new Error('Token余额不足');
  }

  // 更新余额
  await prisma.tokenBalance.update({
    where: { userId },
    data: {
      usedTokens: { increment: amount }
    }
  });

  // 记录使用
  const usage = await prisma.tokenUsage.create({
    data: {
      userId,
      type,
      amount,
      contentLength,
      description
    }
  });

  return usage;
}

// 获取用户配额（兼容旧接口）
export async function getUserQuota(userId: number) {
  const user = await prisma.user.findUnique({
    where: { id: userId }
  });

  if (!user) {
    throw new Error('用户不存在');
  }

  const subscription = await getUserSubscription(userId);
  const tokenBalance = await getUserTokenBalance(userId);
  
  const memberLevel = user.memberLevel as MemberLevel;
  const levelNames = ['免费版', '基础版', '专业版', '旗舰版'];
  
  return {
    level: memberLevel,
    levelName: levelNames[memberLevel] || '免费版',
    isValid: subscription !== null,
    expireAt: subscription?.endDate,
    plan: subscription?.plan ? {
      name: subscription.plan.name,
      features: JSON.parse(subscription.plan.features || '[]')
    } : null,
    tokenBalance,
    limits: subscription?.plan ? {
      dailyGenerations: subscription.plan.dailyGenerations,
      perGenerationLimit: subscription.plan.perGenerationLimit,
      monthlyTokens: subscription.plan.monthlyTokens,
      voiceOptions: subscription.plan.voiceOptions,
      audioQuality: subscription.plan.audioQuality
    } : {
      dailyGenerations: 3,
      perGenerationLimit: 2000,
      monthlyTokens: 10000,
      voiceOptions: 5,
      audioQuality: 'standard'
    }
  };
}

// 检查用户配额
export async function checkQuota(userId: number, requiredTokens: number) {
  const quota = await getUserQuota(userId);
  const balance = quota.tokenBalance;
  
  if (balance.isUnlimited) {
    return { allowed: true, reason: null };
  }
  
  if (balance.remainingTokens < requiredTokens) {
    return { 
      allowed: false, 
      reason: 'Token余额不足',
      required: requiredTokens,
      remaining: balance.remainingTokens
    };
  }
  
  return { allowed: true, reason: null };
}

// ============================================
// 音频时长计费系统（2026-05-20 修正：基于阿里百炼实际定价）
// 成本 = AI文本(qwen-plus ¥2/百万token) + TTS(cosyvoice-v3-flash ¥1/万字符)
// 每分钟(150字): AI≈¥0.0005 + TTS≈¥0.015 = ¥0.0155
// 定价 = 成本 × PRICING_COEFFICIENT（系数可运营调整）
// ============================================

export const AUDIO_BILLING_CONFIG = {
  // 实际API成本：¥0.016/分钟（qwen-plus + cosyvoice-v3-flash）
  costPerMinute: 0.016,
  
  // 定价 = 成本 × 系数（系数可调整）
  // current: ¥0.016 × 2 = ¥0.032/分钟
  pricing: {
    monthly: 0.032,     // 售价 = 成本 × 系数 = ¥0.032/分钟
    overage: 0.048      // 超额价 = 售价 × 1.5 = ¥0.048/分钟
  },
  
  // 语速配置（字/分钟）
  speakingRate: 150,
  
  // 各等级每月音频时长配额（分钟）
  monthlyMinutes: {
    0: 100,    // 免费版：100分钟/月
    1: 300,    // 入门版：300分钟/月
    2: 1000,   // 专业版：1000分钟/月
    3: 4000,   // 旗舰版：4000分钟/月
    4: 15000   // 企业版：15000分钟/月
  },
  
  // 各等级超出配额单价（元/分钟），null=不支持超出
  // 均为售价的1.5倍
  overagePrice: {
    0: null,       // 免费版：不支持超出
    1: 0.048,      // 入门版：¥0.048/分钟
    2: 0.042,      // 专业版：¥0.042/分钟
    3: 0.036,      // 旗舰版：¥0.036/分钟
    4: 0.032       // 企业版：¥0.032/分钟
  }
};

// 根据文本长度计算音频时长
export function calculateAudioDuration(textLength: number): number {
  return Math.ceil(textLength / AUDIO_BILLING_CONFIG.speakingRate);
}

// 计算音频生成费用（支持包月配额和按量计费）
export function calculateAudioCost(
  textLength: number,
  memberLevel: number = 0,
  usedMinutes: number = 0
): {
  textLength: number;
  audioMinutes: number;
  inQuotaMinutes: number;
  overageMinutes: number;
  inQuotaPrice: number;      // 配额内价格
  overagePrice: number;       // 超额价格
  totalPrice: number;
  estimatedCost: number;
} {
  const audioMinutes = calculateAudioDuration(textLength);
  const monthlyMinutes = AUDIO_BILLING_CONFIG.monthlyMinutes[memberLevel] || 10;
  const overagePricePerMinute = AUDIO_BILLING_CONFIG.overagePrice[memberLevel];
  
  // 计算配额内和超额分钟数
  const remainingQuota = Math.max(0, monthlyMinutes - usedMinutes);
  const inQuotaMinutes = Math.min(audioMinutes, remainingQuota);
  const overageMinutes = Math.max(0, audioMinutes - inQuotaMinutes);
  
  // 配额内价格（包月批发价）
  const inQuotaPrice = inQuotaMinutes * AUDIO_BILLING_CONFIG.pricing.monthly;
  
  // 超额价格（按量零售价）
  const overagePrice = overageMinutes > 0 && overagePricePerMinute !== null
    ? overageMinutes * overagePricePerMinute
    : 0;
  
  const totalPrice = Math.round((inQuotaPrice + overagePrice) * 100) / 100;
  
  return {
    textLength,
    audioMinutes,
    inQuotaMinutes,
    overageMinutes,
    inQuotaPrice: Math.round(inQuotaPrice * 100) / 100,
    overagePrice: Math.round(overagePrice * 100) / 100,
    totalPrice,
    estimatedCost: audioMinutes * AUDIO_BILLING_CONFIG.costPerMinute
  };
}

// ============================================
// 风控：额度预检 + 原子预留（防并发超用）
// ============================================
// Token包配置（按量购买，无需订阅）
// 价格 = 月价 × 1.5 倍
// ============================================
export const TOKEN_PACK_CONFIG = {
  minutesPerPack: 100,                // 每包 100 分钟
  unitPriceMonthly: AUDIO_BILLING_CONFIG.pricing.monthly,  // 月价 ¥0.032/分钟
  packPriceMultiplier: 1.5,           // 包价比月价贵 1.5 倍
  get packUnitPrice() {                // 包单价 = 0.032 × 1.5 = ¥0.048/分钟
    return Math.round(this.unitPriceMonthly * this.packPriceMultiplier * 1000) / 1000;
  },
  get packPrice() {                    // 单包价格 = 100 × 0.048 = ¥4.80
    return Math.round(this.minutesPerPack * this.packUnitPrice * 100) / 100;
  },
  get packQuotaValue() {               // 单包额度 = 100 × 0.032 = ¥3.20
    return Math.round(this.minutesPerPack * this.unitPriceMonthly * 100) / 100;
  },
};

// 购买 Token 包（增加用户 costLimit 和 quotaReserved）
export async function purchaseTokenPack(userId: number, quantity: number = 1): Promise<{
  success: boolean;
  message: string;
  data?: { addedQuota: number; totalPaid: number; newCostLimit: number };
}> {
  if (quantity < 1) return { success: false, message: '购买数量至少为1' };

  const pack = TOKEN_PACK_CONFIG;
  const totalPaid = Math.round(pack.packPrice * quantity * 100) / 100;
  const addedQuota = Math.round(pack.packQuotaValue * quantity * 100) / 100;

  // 原子更新 costLimit
  const user = await prisma.user.findUnique({ where: { id: userId } });
  if (!user) return { success: false, message: '用户不存在' };
  if (user.memberLevel === -1) return { success: false, message: 'VIP 无需购买' };

  await prisma.user.update({
    where: { id: userId },
    data: { costLimit: { increment: addedQuota } },
  });

  // 记录购买历史
  await prisma.tokenPackPurchase.create({
    data: {
      userId,
      packMinutes: pack.minutesPerPack,
      quantity,
      unitPrice: pack.packUnitPrice,
      totalAmount: totalPaid,
      addedQuota,
    },
  });

  const newUser = await prisma.user.findUnique({ where: { id: userId }, select: { costLimit: true } });

  console.log(`[TokenPack] 用户#${userId} 购买 ${quantity} 包, 支付 ¥${totalPaid}, 增加额度 ¥${addedQuota}, 总上限 ¥${newUser?.costLimit}`);

  return {
    success: true,
    message: '购买成功',
    data: {
      addedQuota,
      totalPaid,
      newCostLimit: newUser?.costLimit || 0,
    },
  };
}

// 获取购买历史
export async function getTokenPackPurchases(userId: number) {
  return prisma.tokenPackPurchase.findMany({
    where: { userId },
    orderBy: { createdAt: 'desc' },
    take: 50,
  });
}

// 允许 5% 超额缓冲，避免正常并发被误杀
// ============================================
const QUOTA_BUFFER_RATIO = 1.05;

// 获取用户套餐对应的月度费用上限
async function getPlanCostLimit(userId: number): Promise<number> {
  const user = await prisma.user.findUnique({ where: { id: userId }, select: { memberLevel: true, costLimit: true } });
  if (!user) return 0;
  if (user.memberLevel === -1) return Infinity;
  if (user.costLimit > 0) return user.costLimit;
  // 按套餐计算：分钟配额 × 每分钟售价
  const minutes = AUDIO_BILLING_CONFIG.monthlyMinutes[user.memberLevel as MemberLevel] || 10;
  return minutes * AUDIO_BILLING_CONFIG.pricing.monthly;
}

// 原子预留额度（防并发），返回 true=预留成功
export async function atomicReserveQuota(userId: number, estimatedCost: number): Promise<boolean> {
  // VIP 不限
  const user = await prisma.user.findUnique({ where: { id: userId }, select: { memberLevel: true } });
  if (user?.memberLevel === -1) return true;

  // 检查本月是否需要重置
  await ensureMonthlyReset(userId);

  const costLimit = await getPlanCostLimit(userId);
  if (costLimit === Infinity) return true;

  const maxAllowed = costLimit * QUOTA_BUFFER_RATIO;

  // 原子操作：只有 quotaReserved + estimatedCost ≤ maxAllowed 才更新
  const result = await prisma.user.updateMany({
    where: {
      id: userId,
      quotaReserved: { lte: maxAllowed - estimatedCost },
    },
    data: {
      quotaReserved: { increment: estimatedCost },
    },
  });

  return result.count > 0;
}

// 释放预留额度（调用失败时退回）
export async function releaseQuota(userId: number, amount: number): Promise<void> {
  if (amount <= 0) return;
  await prisma.user.updateMany({
    where: { id: userId },
    data: { quotaReserved: { increment: -amount } },
  });
}

// 确保月度重置（每月1日清零 quotaReserved，同步 AiCallLog 实际消耗）
async function ensureMonthlyReset(userId: number): Promise<void> {
  const user = await prisma.user.findUnique({
    where: { id: userId },
    select: { subscriptionResetDate: true, quotaReserved: true },
  });
  if (!user) return;

  const now = new Date();
  const shouldReset = !user.subscriptionResetDate
    || (now.getFullYear() !== user.subscriptionResetDate.getFullYear())
    || (now.getMonth() !== user.subscriptionResetDate.getMonth());

  if (shouldReset) {
    // 重置时同步 AiCallLog 实际消耗
    const actualCost = await getUserMonthlyCost(userId);
    await prisma.user.update({
      where: { id: userId },
      data: {
        quotaReserved: actualCost,  // 从0开始，加上本月已有消耗
        subscriptionResetDate: now,
      },
    });
    console.log(`[Quota] 用户#${userId} 月度额度已重置，本月已有消耗 ¥${actualCost.toFixed(4)}`);
  }
}

// 从 AiCallLog 计算本月实际消耗金额
export async function getUserMonthlyCost(userId: number): Promise<number> {
  const now = new Date();
  const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
  
  const result = await prisma.aiCallLog.aggregate({
    where: {
      userId,
      success: true,
      createdAt: { gte: monthStart },
      callType: { in: ['llm_chat', 'llm_tools', 'tts_synthesize', 'tts_create'] },
    },
    _sum: { estimatedCost: true },
  });
  return result._sum.estimatedCost || 0;
}

// 获取用户音频时长余额（基于 AiCallLog 真实消耗 + 原子预留）
export async function getUserAudioBalance(userId: number) {
  const user = await prisma.user.findUnique({
    where: { id: userId }
  });
  
  if (!user) {
    throw new Error('用户不存在');
  }
  
  const memberLevel = user.memberLevel as MemberLevel;
  if (memberLevel === -1) {
    return { memberLevel: -1, totalMinutes: -1, usedMinutes: 0, remainingMinutes: -1, overageEnabled: false, overagePrice: 0, resetDate: null, monthlyCost: 0, costLimit: Infinity, quotaReserved: 0 };
  }
  
  const monthlyMinutes = AUDIO_BILLING_CONFIG.monthlyMinutes[memberLevel] || 10;
  const overageEnabled = AUDIO_BILLING_CONFIG.overagePrice[memberLevel] !== null;
  const overagePrice = AUDIO_BILLING_CONFIG.overagePrice[memberLevel];
  const perMinutePrice = AUDIO_BILLING_CONFIG.pricing.monthly;
  const costLimit = await getPlanCostLimit(userId);
  
  // 确保月度重置
  await ensureMonthlyReset(userId);
  
  // 刷新 user 获取最新 quotaReserved
  const refreshed = await prisma.user.findUnique({ where: { id: userId }, select: { quotaReserved: true } });
  const quotaReserved = refreshed?.quotaReserved || 0;
  const monthlyCost = await getUserMonthlyCost(userId);
  const usedMinutes = perMinutePrice > 0 ? Math.ceil(quotaReserved / perMinutePrice) : 0;
  
  return {
    memberLevel,
    totalMinutes: monthlyMinutes,
    usedMinutes,
    remainingMinutes: monthlyMinutes - usedMinutes,
    overageEnabled,
    overagePrice: overagePrice || 0,
    resetDate: user.subscriptionResetDate,
    monthlyCost: Math.round(monthlyCost * 100) / 100,
    costLimit,
    quotaReserved: Math.round(quotaReserved * 10000) / 10000,
  };
}

// 检查音频生成配额
// 检查音频生成配额（只检查月度总配额，无单次限制）
export async function checkAudioQuota(
  userId: number,
  textLength: number
) {
  const audioMinutes = calculateAudioDuration(textLength);
  const balance = await getUserAudioBalance(userId);
  
  // 测试账号：无限额度
  if (balance.totalMinutes === -1) {
    return { allowed: true, reason: null, audioMinutes, remainingMinutes: -1, totalMinutes: -1 };
  }
  
  // 免费版不支持超出配额
  if (balance.remainingMinutes < audioMinutes && !balance.overageEnabled) {
    return {
      allowed: false,
      reason: `音频时长不足，本月配额已用完（${balance.totalMinutes}分钟）`,
      audioMinutes,
      remainingMinutes: balance.remainingMinutes,
      totalMinutes: balance.totalMinutes,
      overageEnabled: false
    };
  }
  
  return {
    allowed: true,
    reason: null,
    audioMinutes,
    inQuotaMinutes: Math.min(audioMinutes, balance.remainingMinutes),
    overageMinutes: Math.max(0, audioMinutes - balance.remainingMinutes),
    remainingMinutes: balance.remainingMinutes,
    totalMinutes: balance.totalMinutes,
    overageEnabled: balance.overageEnabled,
    overagePrice: balance.overagePrice
  };
}

// 扣除音频时长（生成完成后调用）
export async function consumeAudioMinutes(
  userId: number,
  textLength: number,
  description?: string
) {
  const audioMinutes = calculateAudioDuration(textLength);
  const balance = await getUserAudioBalance(userId);
  const cost = calculateAudioCost(textLength, balance.memberLevel, balance.usedMinutes);
  
  // 更新用户已使用时长
  await prisma.user.update({
    where: { id: userId },
    data: {
      usedAudioMinutes: { increment: audioMinutes }
    }
  });
  
  // 记录使用日志
  const usage = await prisma.tokenUsage.create({
    data: {
      userId,
      type: 'audio_generation',
      amount: audioMinutes,
      contentLength: textLength,
      description: description || `${audioMinutes}分钟音频`
    }
  });
  
  return {
    usageId: usage.id,
    audioMinutes,
    textLength,
    inQuotaMinutes: cost.inQuotaMinutes,
    overageMinutes: cost.overageMinutes,
    inQuotaPrice: cost.inQuotaPrice,
    overagePrice: cost.overagePrice,
    totalPrice: cost.totalPrice
  };
}

// 获取音频生成预估（用于UI展示）
export async function getAudioEstimate(
  userId: number,
  textLength: number
) {
  const balance = await getUserAudioBalance(userId);
  const cost = calculateAudioCost(textLength, balance.memberLevel, balance.usedMinutes);
  const quota = await checkAudioQuota(userId, textLength);
  
  return {
    // 预估信息
    textLength,
    audioMinutes: cost.audioMinutes,
    inQuotaMinutes: cost.inQuotaMinutes,
    overageMinutes: cost.overageMinutes,
    inQuotaPrice: cost.inQuotaPrice,
    overagePricePerMinute: cost.overagePrice,
    estimatedPrice: cost.totalPrice,
    estimatedCost: cost.estimatedCost,
    
    // 用户配额
    remainingMinutes: balance.remainingMinutes,
    totalMinutes: balance.totalMinutes,
    usedMinutes: balance.usedMinutes,
    
    // 计费策略
    overageEnabled: balance.overageEnabled,
    overagePrice: balance.overagePrice,
    
    // 是否允许生成
    canGenerate: quota.allowed,
    reason: quota.reason,
    
    // 显示文本
    displayText: quota.allowed
      ? cost.overageMinutes > 0
        ? `预计${cost.audioMinutes}分钟（配额${cost.inQuotaMinutes}分钟+超出${cost.overageMinutes}分钟），约¥${cost.totalPrice}`
        : `预计${cost.audioMinutes}分钟，约¥${cost.totalPrice}`
      : quota.reason
  };
}

// ============================================
// 书籍生成配额系统（字数预估 + 过程监控 + 中断保存）
// ============================================

import { estimateBookWords as estimateBookWordsFromConfig, getBookTypeConfig as getBookTypeConfigFromNew } from '../book-generator/book-type-config';

// 根据书籍规模计算预估字数（使用统一配置）
export function estimateBookWords(bookScale: string): { min: number; max: number; avg: number } {
  return estimateBookWordsFromConfig(bookScale);
}

// 根据预估字数计算预估音频时长
export function estimateAudioMinutesFromWords(wordCount: number): number {
  return Math.ceil(wordCount / AUDIO_BILLING_CONFIG.speakingRate);
}

// 检查书籍生成的配额（生成前预估）
export async function checkBookGenerationQuota(
  userId: number,
  bookScale: string
): Promise<{
  allowed: boolean;
  reason: string | null;
  // 预估信息
  estimatedWords: { min: number; max: number; avg: number };
  estimatedAudioMinutes: { min: number; max: number; avg: number };
  // 配额信息
  quota: {
    totalMinutes: number;
    usedMinutes: number;
    remainingMinutes: number;
    overageEnabled: boolean;
    overagePrice: number;
  };
  // 费用预估
  costEstimate: {
    inQuotaMinutes: number;
    overageMinutes: number;
    estimatedPrice: number;
    displayText: string;
  };
}> {
  const wordEstimate = estimateBookWords(bookScale);
  const audioMinutes = estimateAudioMinutesFromWords(wordEstimate.avg);
  const balance = await getUserAudioBalance(userId);
  
  // 免费版且预估超出配额
  if (!balance.overageEnabled && balance.remainingMinutes < audioMinutes) {
    return {
      allowed: false,
      reason: `免费版不支持超出配额，请升级套餐或减少书籍规模`,
      estimatedWords: wordEstimate,
      estimatedAudioMinutes: {
        min: estimateAudioMinutesFromWords(wordEstimate.min),
        max: estimateAudioMinutesFromWords(wordEstimate.max),
        avg: audioMinutes
      },
      quota: {
        totalMinutes: balance.totalMinutes,
        usedMinutes: balance.usedMinutes,
        remainingMinutes: balance.remainingMinutes,
        overageEnabled: balance.overageEnabled,
        overagePrice: balance.overagePrice
      },
      costEstimate: {
        inQuotaMinutes: balance.remainingMinutes,
        overageMinutes: 0,
        estimatedPrice: 0,
        displayText: `预估需要${audioMinutes}分钟，超出您的配额${balance.remainingMinutes}分钟`
      }
    };
  }
  
  // 计算费用
  const inQuotaMinutes = Math.min(audioMinutes, balance.remainingMinutes);
  const overageMinutes = Math.max(0, audioMinutes - balance.remainingMinutes);
  const estimatedPrice = overageMinutes > 0 && balance.overagePrice
    ? overageMinutes * balance.overagePrice
    : 0;
  
  return {
    allowed: true,
    reason: null,
    estimatedWords: wordEstimate,
    estimatedAudioMinutes: {
      min: estimateAudioMinutesFromWords(wordEstimate.min),
      max: estimateAudioMinutesFromWords(wordEstimate.max),
      avg: audioMinutes
    },
    quota: {
      totalMinutes: balance.totalMinutes,
      usedMinutes: balance.usedMinutes,
      remainingMinutes: balance.remainingMinutes,
      overageEnabled: balance.overageEnabled,
      overagePrice: balance.overagePrice
    },
    costEstimate: {
      inQuotaMinutes,
      overageMinutes,
      estimatedPrice: Math.round(estimatedPrice * 100) / 100,
      displayText: overageMinutes > 0
        ? `预估${audioMinutes}分钟（配额${inQuotaMinutes}分钟+超出${overageMinutes}分钟），预计额外费用¥${estimatedPrice}`
        : `预估${audioMinutes}分钟，配额内免费`
    }
  };
}

// 检查当前额度是否足够生成指定字数（用于生成过程监控）
export async function checkQuotaForWords(userId: number, wordCount: number): Promise<{
  sufficient: boolean;
  reason: string | null;
  currentWords: number;
  maxAllowedWords: number;
  audioMinutesNeeded: number;
  remainingMinutes: number;
}> {
  const audioMinutesNeeded = estimateAudioMinutesFromWords(wordCount);
  const balance = await getUserAudioBalance(userId);
  
  if (!balance.overageEnabled && balance.remainingMinutes < audioMinutesNeeded) {
    return {
      sufficient: false,
      reason: `额度不足：需要${audioMinutesNeeded}分钟，您剩余${balance.remainingMinutes}分钟`,
      currentWords: wordCount,
      maxAllowedWords: balance.remainingMinutes * AUDIO_BILLING_CONFIG.speakingRate,
      audioMinutesNeeded,
      remainingMinutes: balance.remainingMinutes
    };
  }
  
  return {
    sufficient: true,
    reason: null,
    currentWords: wordCount,
    maxAllowedWords: balance.remainingMinutes * AUDIO_BILLING_CONFIG.speakingRate,
    audioMinutesNeeded,
    remainingMinutes: balance.remainingMinutes
  };
}

// 获取当前用户已生成的字数（用于断点续传）
export async function getGeneratedWordCount(bookId: string): Promise<number> {
  const book = await prisma.book.findUnique({
    where: { id: parseInt(bookId) },
    include: { chapters: true }
  });
  
  if (!book) return 0;
  
  // 统计已完成章节的字数（genStage 含内容/音频/视频阶段都算已完成）
  const completedGenStages = ['content_completed', 'audio_completed', 'audio_generating', 'video_generating', 'video_completed'];
  const completedWords = book.chapters
    .filter(c => completedGenStages.includes(c.genStage))
    .reduce((sum, c) => sum + (c.wordCount || 0), 0);
  
  return completedWords;
}

// 记录生成中断状态（用于断点续传）
export async function markGenerationInterrupted(bookId: string, lastChapterNumber: number, currentWords: number): Promise<void> {
  await prisma.book.update({
    where: { id: parseInt(bookId) },
    data: {
      genStage: 'failed',
      failedStage: 'content_generating',
      errorMsg: `额度不足中断，已生成${currentWords}字`,
      progress: 0 // 重置进度，下次生成时重新计算
    }
  });
  
  console.log(`[QuotaCheck] 书籍${bookId}生成中断：已完成${currentWords}字，最后章节${lastChapterNumber}`);
}
