/**
 * Subscription Service 单元测试
 * 测试配额计算、扣除、边界情况
 */

import { describe, it, expect, beforeEach, vi } from 'vitest';
import {
  calculateAudioDuration,
  calculateAudioCost,
  AUDIO_BILLING_CONFIG,
  TOKEN_COST_CONFIG,
  calculateTokenCost,
} from '@/modules/subscription/subscription.service';

// Mock Prisma
vi.mock('@/models', () => ({
  prisma: {
    user: {
      findUnique: vi.fn(),
      update: vi.fn(),
    },
    tokenUsage: {
      create: vi.fn(),
      count: vi.fn(),
    },
    subscriptionPlan: {
      findUnique: vi.fn(),
      findMany: vi.fn(),
    },
    subscription: {
      findFirst: vi.fn(),
    },
    tokenBalance: {
      findUnique: vi.fn(),
      create: vi.fn(),
      update: vi.fn(),
    },
  },
}));

describe('AUDIO_BILLING_CONFIG', () => {
  it('包含所有会员等级的配置', () => {
    expect(AUDIO_BILLING_CONFIG.monthlyMinutes).toHaveProperty('0'); // 免费版
    expect(AUDIO_BILLING_CONFIG.monthlyMinutes).toHaveProperty('1'); // 入门版
    expect(AUDIO_BILLING_CONFIG.monthlyMinutes).toHaveProperty('2'); // 专业版
    expect(AUDIO_BILLING_CONFIG.monthlyMinutes).toHaveProperty('3'); // 旗舰版
    expect(AUDIO_BILLING_CONFIG.monthlyMinutes).toHaveProperty('4'); // 企业版
  });

  it('免费版不支持超额', () => {
    expect(AUDIO_BILLING_CONFIG.overagePrice[0]).toBeNull();
  });

  it('其他等级支持超额', () => {
    // 实际值：入门版¥0.048, 专业版¥0.042, 旗舰版¥0.036, 企业版¥0.032
    expect(AUDIO_BILLING_CONFIG.overagePrice[1]).toBe(0.048);
    expect(AUDIO_BILLING_CONFIG.overagePrice[2]).toBe(0.042);
    expect(AUDIO_BILLING_CONFIG.overagePrice[3]).toBe(0.036);
    expect(AUDIO_BILLING_CONFIG.overagePrice[4]).toBe(0.032);
  });
});

describe('calculateAudioDuration', () => {
  it('按语速 150 字/分钟 计算', () => {
    expect(calculateAudioDuration(150)).toBe(1);  // 150字 = 1分钟
    expect(calculateAudioDuration(300)).toBe(2);  // 300字 = 2分钟
    expect(calculateAudioDuration(450)).toBe(3);  // 450字 = 3分钟
  });

  it('向上取整', () => {
    expect(calculateAudioDuration(1)).toBe(1);    // 不足1分钟按1分钟计
    expect(calculateAudioDuration(151)).toBe(2);  // 151字按2分钟计
    expect(calculateAudioDuration(299)).toBe(2);  // 299字按2分钟计
  });

  it('大文本计算正确', () => {
    expect(calculateAudioDuration(1500)).toBe(10); // 1500字 = 10分钟
    expect(calculateAudioDuration(15000)).toBe(100); // 15000字 = 100分钟
  });
});

describe('calculateAudioCost', () => {
  // 实际定价：¥0.032/分钟（成本¥0.016 × 2）
  const PRICE_PER_MIN = 0.032;

  describe('正常计算', () => {
    it('免费用户 0 已用，配额内计算', () => {
      const result = calculateAudioCost(1500, 0, 0); // 1500字，10分钟音频
      expect(result.audioMinutes).toBe(10);
      expect(result.inQuotaMinutes).toBe(10);
      expect(result.overageMinutes).toBe(0);
      expect(result.inQuotaPrice).toBeCloseTo(10 * PRICE_PER_MIN, 4); // 10分钟 × ¥0.032/分钟
      expect(result.overagePrice).toBe(0);
      expect(result.totalPrice).toBe(result.inQuotaPrice);
    });

    it('专业版用户 100分钟配额', () => {
      const result = calculateAudioCost(15000, 2, 0); // 15000字，100分钟
      expect(result.audioMinutes).toBe(100);
      expect(result.inQuotaMinutes).toBe(100);
      expect(result.overageMinutes).toBe(0);
      expect(result.inQuotaPrice).toBeCloseTo(100 * PRICE_PER_MIN, 3); // 100分钟 × ¥0.032/分钟
      expect(result.totalPrice).toBe(result.inQuotaPrice);
    });
  });

  describe('超额计费', () => {
    it('入门版用户超额使用', () => {
      // 入门版 30分钟配额，已用20分钟，生成40分钟音频
      const result = calculateAudioCost(6000, 1, 20);
      expect(result.audioMinutes).toBe(40);
      expect(result.inQuotaMinutes).toBe(10);  // 剩余10分钟配额
      expect(result.overageMinutes).toBe(30);  // 超额30分钟
      // 配额内价格 = 10分钟 × ¥0.032 = ¥0.32
      expect(result.inQuotaPrice).toBeCloseTo(0.32, 3);
      // 超额价格 = 30分钟 × ¥0.048 = ¥1.44
      expect(result.overagePrice).toBeCloseTo(1.44, 3);
      expect(result.totalPrice).toBeCloseTo(1.76, 3); // 0.32 + 1.44
    });

    it('专业版用户超额使用', () => {
      // 专业版 100分钟配额，已用50分钟，生成80分钟音频
      const result = calculateAudioCost(12000, 2, 50);
      expect(result.audioMinutes).toBe(80);
      expect(result.inQuotaMinutes).toBe(50);  // 剩余50分钟配额
      expect(result.overageMinutes).toBe(30);  // 超额30分钟
      // 配额内价格 = 50分钟 × ¥0.032 = ¥1.6
      expect(result.inQuotaPrice).toBeCloseTo(1.6, 3);
      // 超额价格 = 30分钟 × ¥0.042 = ¥1.26
      expect(result.overagePrice).toBeCloseTo(1.26, 3);
      expect(result.totalPrice).toBeCloseTo(2.86, 3); // 1.6 + 1.26
    });
  });

  describe('边界值', () => {
    it('刚好等于配额上限', () => {
      // 免费版 10分钟配额，已用0分钟，生成10分钟音频
      const result = calculateAudioCost(1500, 0, 0);
      expect(result.inQuotaMinutes).toBe(10);
      expect(result.overageMinutes).toBe(0);
      expect(result.totalPrice).toBeCloseTo(0.32, 3); // 10分钟 × ¥0.032
    });

    it('超出配额 1 分钟', () => {
      // 免费版 10分钟配额，已用0分钟，生成11分钟音频
      const result = calculateAudioCost(1650, 0, 0);
      expect(result.audioMinutes).toBe(11);
      expect(result.inQuotaMinutes).toBe(10);  // 只能使用10分钟配额
      expect(result.overageMinutes).toBe(1); // 超额1分钟
      // 免费版不支持超额，所以超额价格为0
      expect(result.overagePrice).toBe(0);
    });

    it('配额已用尽', () => {
      // 免费版 10分钟配额，已用10分钟，生成5分钟音频
      const result = calculateAudioCost(750, 0, 10);
      expect(result.audioMinutes).toBe(5);
      expect(result.inQuotaMinutes).toBe(0);
      expect(result.overageMinutes).toBe(5);
      // 免费版不支持超额
      expect(result.overagePrice).toBe(0);
    });
  });

  describe('免费版不支持超额', () => {
    it('免费版超额部分价格为零', () => {
      const result = calculateAudioCost(3000, 0, 0); // 20分钟音频
      expect(result.overageMinutes).toBe(10);
      expect(result.overagePrice).toBe(0); // 免费版不支持超额
    });

    it('免费版总价为配额内价格', () => {
      const result = calculateAudioCost(3000, 0, 0);
      expect(result.totalPrice).toBe(result.inQuotaPrice);
    });
  });

  describe('estimatedCost 计算', () => {
    it('estimatedCost 基于成本价计算', () => {
      const result = calculateAudioCost(1500, 0, 0);
      // 10分钟 × ¥0.016/分钟(成本) = ¥0.16
      expect(result.estimatedCost).toBeCloseTo(10 * AUDIO_BILLING_CONFIG.costPerMinute, 4);
    });
  });
});

describe('calculateTokenCost', () => {
  it('默认使用 qwen_plus 模型计算', () => {
    const result = calculateTokenCost(1000); // 1000字
    expect(result.aiInputCost).toBeGreaterThan(0);
    expect(result.aiOutputCost).toBeGreaterThan(0);
    const expected = result.aiInputCost + result.aiOutputCost + result.ttsCost;
    expect(result.totalCost).toBeCloseTo(expected, 4);
    expect(result.suggestedPrice).toBeGreaterThan(result.totalCost); // 有利润
  });

  it('不同模型成本不同', () => {
    const resultQwen = calculateTokenCost(1000, 'qwen_plus');
    const resultQwenFlash = calculateTokenCost(1000, 'qwen3_flash');
    const resultDeepseek = calculateTokenCost(1000, 'deepseek_v3');

    // 各模型定价不同，成本应该不同
    expect(resultQwen.totalCost).not.toBe(resultQwenFlash.totalCost);
    expect(resultQwen.totalCost).not.toBe(resultDeepseek.totalCost);
    expect(resultQwenFlash.totalCost).not.toBe(resultDeepseek.totalCost);
  });

  it('大文本计算正确', () => {
    const result = calculateTokenCost(10000);
    // 10000字 → 15000 tokens
    // AI输入: 15000 * 0.1 / 1M * 0.8 = 0.0012
    // AI输出: 15000 / 1M * 2.0 = 0.03
    // TTS: 10000/10000 * 1.0 = 1.0
    // totalCost ≈ 1.0312
    expect(result.totalCost).toBeGreaterThan(0);
    expect(result.ttsCost).toBeGreaterThan(0);
  });

  it('返回值格式正确', () => {
    const result = calculateTokenCost(1000);
    expect(result).toHaveProperty('aiInputCost');
    expect(result).toHaveProperty('aiOutputCost');
    expect(result).toHaveProperty('ttsCost');
    expect(result).toHaveProperty('totalCost');
    expect(result).toHaveProperty('suggestedPrice');
  });
});

describe('配额计算边界情况', () => {
  it('零文本', () => {
    const result = calculateAudioCost(0, 0, 0);
    expect(result.audioMinutes).toBe(0);
    expect(result.totalPrice).toBe(0);
  });

  it('负数文本返回0或负0', () => {
    const result = calculateAudioCost(-100, 0, 0);
    expect(result.audioMinutes).toBeLessThanOrEqual(0);
  });

  it('未知会员等级使用默认配额', () => {
    const result = calculateAudioCost(1500, 99, 0); // 未知等级
    expect(result.audioMinutes).toBe(10);
    // 默认配额为免费版10分钟
  });

  it('所有金额精确到分', () => {
    const result = calculateAudioCost(333, 1, 0); // 不规则数字
    // 检查金额没有精度问题
    const strTotal = result.totalPrice.toString();
    const decimals = strTotal.includes('.') ? strTotal.split('.')[1].length : 0;
    expect(decimals).toBeLessThanOrEqual(2);
  });
});