/**
 * 数据库集成测试 - Prisma CRUD 操作
 * 测试真实的数据库操作，包括事务和回滚
 */

import { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } from 'vitest';
import { PrismaClient } from '@prisma/client';

const TEST_DATABASE_URL = process.env.TEST_DATABASE_URL || 'mysql://root:@localhost:3307/audio_book_test';

const db = new PrismaClient({
  datasources: {
    db: { url: TEST_DATABASE_URL }
  }
});

describe('Prisma CRUD 集成测试', () => {
  beforeAll(async () => {
    await db.$connect();
  });

  afterAll(async () => {
    await db.$disconnect();
  });

  beforeEach(async () => {
    await db.$executeRawUnsafe('BEGIN');
  });

  afterEach(async () => {
    await db.$executeRawUnsafe('ROLLBACK');
  });

  describe('User CRUD', () => {
    it('创建用户并查询', async () => {
      const phone = `138${Date.now()}`.slice(0, 11);
      const user = await db.user.create({
        data: {
          phone,
          nickname: `测试用户_${Date.now()}`,
          memberLevel: 0,
          dailyUsage: 0,
        }
      });

      expect(user.id).toBeDefined();
      expect(user.phone).toBe(phone);
      expect(user.memberLevel).toBe(0);

      const found = await db.user.findUnique({ where: { id: user.id } });
      expect(found).not.toBeNull();
      expect(found?.phone).toBe(phone);
    });

    it('更新用户会员等级', async () => {
      const phone = `138${Date.now()}`.slice(0, 11);
      const user = await db.user.create({
        data: {
          phone,
          nickname: `测试用户_${Date.now()}`,
          memberLevel: 0,
          dailyUsage: 0,
        }
      });

      const updated = await db.user.update({
        where: { id: user.id },
        data: { memberLevel: 2 }
      });

      expect(updated.memberLevel).toBe(2);
    });

    it('软删除用户', async () => {
      const phone = `138${Date.now()}`.slice(0, 11);
      const user = await db.user.create({
        data: {
          phone,
          nickname: `测试用户_${Date.now()}`,
          memberLevel: 0,
          dailyUsage: 0,
          deletedAt: null,
        }
      });

      await db.user.update({
        where: { id: user.id },
        data: { deletedAt: new Date() }
      });

      const found = await db.user.findUnique({ where: { id: user.id } });
      expect(found?.deletedAt).not.toBeNull();
    });

    it('唯一索引冲突 - 重复手机号', async () => {
      const phone = `138${Date.now()}`.slice(0, 11);
      await db.user.create({
        data: {
          phone,
          nickname: '用户1',
          memberLevel: 0,
          dailyUsage: 0,
        }
      });

      await expect(
        db.user.create({
          data: {
            phone,
            nickname: '用户2',
            memberLevel: 0,
            dailyUsage: 0,
          }
        })
      ).rejects.toThrow();
    });
  });

  describe('Book + Chapter 关联查询', () => {
    it('创建书籍时级联创建章节', async () => {
      const phone = `138${Date.now()}`.slice(0, 11);
      const user = await db.user.create({
        data: {
          phone,
          nickname: `测试用户_${Date.now()}`,
          memberLevel: 0,
          dailyUsage: 0,
        }
      });

      const book = await db.book.create({
        data: {
          userId: user.id,
          title: `测试书籍_${Date.now()}`,
          description: '测试描述',
          totalChapters: 3,
          estimatedWords: 30000,
          status: 'draft',
        }
      });

      const chapter1 = await db.bookChapter.create({
        data: {
          bookId: book.id,
          chapterIndex: 1,
          title: '第一章',
          genStage: 'idle',
        }
      });

      const chapter2 = await db.bookChapter.create({
        data: {
          bookId: book.id,
          chapterIndex: 2,
          title: '第二章',
          genStage: 'idle',
        }
      });

      expect(chapter1.id).toBeDefined();
      expect(chapter2.id).toBeDefined();
      expect(chapter1.bookId).toBe(book.id);
    });

    it('查询书籍时包含所有章节', async () => {
      const phone = `138${Date.now()}`.slice(0, 11);
      const user = await db.user.create({
        data: {
          phone,
          nickname: `测试用户_${Date.now()}`,
          memberLevel: 0,
          dailyUsage: 0,
        }
      });

      const book = await db.book.create({
        data: {
          userId: user.id,
          title: `测试书籍_${Date.now()}`,
          description: '测试描述',
          totalChapters: 2,
          estimatedWords: 20000,
          status: 'draft',
        }
      });

      await db.bookChapter.createMany({
        data: [
          { bookId: book.id, chapterIndex: 1, title: '第一章', genStage: 'idle' },
          { bookId: book.id, chapterIndex: 2, title: '第二章', genStage: 'idle' },
        ]
      });

      const found = await db.book.findUnique({
        where: { id: book.id },
        include: { chapters: true }
      });

      expect(found).not.toBeNull();
      expect(found?.chapters).toHaveLength(2);
    });

    it('删除书籍时级联删除章节', async () => {
      const phone = `138${Date.now()}`.slice(0, 11);
      const user = await db.user.create({
        data: {
          phone,
          nickname: `测试用户_${Date.now()}`,
          memberLevel: 0,
          dailyUsage: 0,
        }
      });

      const book = await db.book.create({
        data: {
          userId: user.id,
          title: `测试书籍_${Date.now()}`,
          description: '测试描述',
          totalChapters: 2,
          estimatedWords: 20000,
          status: 'draft',
        }
      });

      await db.bookChapter.createMany({
        data: [
          { bookId: book.id, chapterIndex: 1, title: '第一章', genStage: 'idle' },
          { bookId: book.id, chapterIndex: 2, title: '第二章', genStage: 'idle' },
        ]
      });

      // 删除书籍（不级联删除，需要手动删除章节）
      await db.book.delete({ where: { id: book.id } });

      const chapters = await db.bookChapter.findMany({ where: { bookId: book.id } });
      expect(chapters).toHaveLength(0);
    });
  });

  describe('事务', () => {
    it('事务失败时全部回滚', async () => {
      const phone1 = `138${Date.now()}`.slice(0, 11);
      const phone2 = `138${Date.now() + 1}`.slice(0, 11);

      const user1 = await db.user.create({
        data: {
          phone: phone1,
          nickname: `用户1_${Date.now()}`,
          memberLevel: 0,
          dailyUsage: 0,
        }
      });

      try {
        await db.$transaction([
          db.user.update({
            where: { id: user1.id },
            data: { memberLevel: 1 }
          }),
          db.user.create({
            data: {
              phone: phone2,
              nickname: `用户2_${Date.now()}`,
              memberLevel: 0,
              dailyUsage: 0,
            }
          }),
          db.user.create({
            data: {
              phone: phone2, // 重复手机号，应该失败
              nickname: `用户2重复_${Date.now()}`,
              memberLevel: 0,
              dailyUsage: 0,
            }
          }),
        ]);
      } catch (e) {
        // 预期失败
      }

      // 检查第一个用户的等级没有被修改（事务回滚）
      const found = await db.user.findUnique({ where: { id: user1.id } });
      expect(found?.memberLevel).toBe(0);
    });

    it('并发事务不互相干扰', async () => {
      const phone = `138${Date.now()}`.slice(0, 11);

      const user = await db.user.create({
        data: {
          phone,
          nickname: `测试用户_${Date.now()}`,
          memberLevel: 0,
          dailyUsage: 0,
        }
      });

      // 并发更新
      const [result1, result2] = await Promise.all([
        db.user.update({
          where: { id: user.id },
          data: { dailyUsage: { increment: 1 } }
        }),
        db.user.update({
          where: { id: user.id },
          data: { dailyUsage: { increment: 2 } }
        }),
      ]);

      // 最终值应该是 3（1 + 2）
      const final = await db.user.findUnique({ where: { id: user.id } });
      expect(final?.dailyUsage).toBeGreaterThanOrEqual(3);
    });
  });

  describe('Token 余额操作', () => {
    it('创建 TokenBalance', async () => {
      const phone = `138${Date.now()}`.slice(0, 11);
      const user = await db.user.create({
        data: {
          phone,
          nickname: `测试用户_${Date.now()}`,
          memberLevel: 0,
          dailyUsage: 0,
        }
      });

      const balance = await db.tokenBalance.create({
        data: {
          userId: user.id,
          totalTokens: 10000,
          usedTokens: 0,
        }
      });

      expect(balance.id).toBeDefined();
      expect(balance.totalTokens).toBe(10000);
      expect(balance.usedTokens).toBe(0);
    });

    it('扣除 Token', async () => {
      const phone = `138${Date.now()}`.slice(0, 11);
      const user = await db.user.create({
        data: {
          phone,
          nickname: `测试用户_${Date.now()}`,
          memberLevel: 0,
          dailyUsage: 0,
        }
      });

      const balance = await db.tokenBalance.create({
        data: {
          userId: user.id,
          totalTokens: 10000,
          usedTokens: 0,
        }
      });

      await db.tokenBalance.update({
        where: { id: balance.id },
        data: { usedTokens: { increment: 500 } }
      });

      const updated = await db.tokenBalance.findUnique({ where: { id: balance.id } });
      expect(updated?.usedTokens).toBe(500);
      expect(updated?.totalTokens - updated!.usedTokens).toBe(9500);
    });
  });
});