import { Controller, Get, Post, Param, Query, Body, NotFoundException, BadRequestException } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery } from '@nestjs/swagger';
import { IsString, IsOptional } from 'class-validator';
import { GetMiningAccountQuery } from '../../application/queries/get-mining-account.query';
import { GetMiningStatsQuery } from '../../application/queries/get-mining-stats.query';
import { Public } from '../../shared/guards/jwt-auth.guard';
import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service';
import { Decimal } from '@prisma/client/runtime/library';

class TransferDto {
  @IsString()
  amount: string;

  @IsString()
  @IsOptional()
  transferNo?: string;
}

@ApiTags('Mining')
@Controller('mining')
@Public()  // 服务间调用，不需要认证
export class MiningController {
  constructor(
    private readonly getAccountQuery: GetMiningAccountQuery,
    private readonly getStatsQuery: GetMiningStatsQuery,
    private readonly prisma: PrismaService,
  ) {}

  @Get('stats')
  @ApiOperation({ summary: '获取挖矿统计数据' })
  @ApiResponse({ status: 200, description: '挖矿统计' })
  async getStats() {
    return this.getStatsQuery.execute();
  }

  @Get('progress')
  @ApiOperation({ summary: '获取挖矿进度状态（类似销毁进度）' })
  @ApiResponse({ status: 200, description: '挖矿进度状态' })
  async getMiningProgress() {
    const config = await this.prisma.miningConfig.findFirst();
    if (!config) {
      return {
        totalDistributed: '0',
        distributionPool: '0',
        remainingDistribution: '0',
        miningProgress: '0',
        minuteDistribution: '0',
        remainingMinutes: 0,
        lastMiningMinute: null,
        isActive: false,
        currentEra: 0,
      };
    }

    // 查询用户挖矿账户的总已挖数量
    const userMiningStats = await this.prisma.miningAccount.aggregate({
      _sum: { totalMined: true },
    });

    // 查询系统账户的总已挖数量
    const systemMiningStats = await this.prisma.systemMiningAccount.aggregate({
      _sum: { totalMined: true },
    });

    // 总已分配 = 用户已挖 + 系统已挖
    const totalDistributedDecimal =
      Number(userMiningStats._sum.totalMined || 0) +
      Number(systemMiningStats._sum.totalMined || 0);

    // 查询最后分配时间
    const lastMinuteStat = await this.prisma.minuteMiningStat.findFirst({
      orderBy: { minute: 'desc' },
      select: { minute: true },
    });

    // 计算每分钟分配量（每秒 × 60）
    const secondDistribution = Number(config.secondDistribution || 0);
    const minuteDistribution = secondDistribution * 60;

    // 计算挖矿进度（用实际已分配数量 / 分配池总量）
    const distributionPool = Number(config.distributionPool || 0);
    // 剩余分配池 = 总池 - 实际已分配（保持数据一致性）
    const remainingDistribution = Math.max(0, distributionPool - totalDistributedDecimal);
    const miningProgress = distributionPool > 0 ? (totalDistributedDecimal / distributionPool) * 100 : 0;

    // 计算剩余分钟数
    const remainingMinutes = minuteDistribution > 0 ? Math.ceil(remainingDistribution / minuteDistribution) : 0;

    return {
      totalDistributed: totalDistributedDecimal.toFixed(8),
      distributionPool: distributionPool.toFixed(8),
      remainingDistribution: remainingDistribution.toFixed(8),
      miningProgress: miningProgress.toFixed(4),
      minuteDistribution: minuteDistribution.toFixed(8),
      remainingMinutes,
      lastMiningMinute: lastMinuteStat?.minute || null,
      isActive: config.isActive,
      currentEra: config.currentEra,
    };
  }

  @Get('ranking')
  @ApiOperation({ summary: '获取挖矿排行榜' })
  @ApiQuery({ name: 'limit', required: false, description: '返回数量限制', type: Number })
  @ApiResponse({ status: 200, description: '挖矿排行榜' })
  async getRanking(@Query('limit') limit?: number) {
    const ranking = await this.getStatsQuery.getRanking(limit ?? 100);
    return { data: ranking };
  }

  @Get('accounts/:accountSequence')
  @ApiOperation({ summary: '获取挖矿账户信息' })
  @ApiParam({ name: 'accountSequence', description: '账户序号' })
  @ApiResponse({ status: 200, description: '挖矿账户信息' })
  @ApiResponse({ status: 404, description: '账户不存在' })
  async getAccount(@Param('accountSequence') accountSequence: string) {
    const account = await this.getAccountQuery.execute(accountSequence);
    if (!account) {
      throw new NotFoundException(`Account ${accountSequence} not found`);
    }
    return account;
  }

  @Get('accounts/:accountSequence/records')
  @ApiOperation({ summary: '获取挖矿记录' })
  @ApiParam({ name: 'accountSequence', description: '账户序号' })
  @ApiQuery({ name: 'page', required: false, type: Number })
  @ApiQuery({ name: 'pageSize', required: false, type: Number })
  @ApiResponse({ status: 200, description: '挖矿记录列表' })
  async getRecords(
    @Param('accountSequence') accountSequence: string,
    @Query('page') page?: number,
    @Query('pageSize') pageSize?: number,
  ) {
    return this.getAccountQuery.getMiningRecords(
      accountSequence,
      page ?? 1,
      pageSize ?? 50,
    );
  }

  @Get('accounts/:accountSequence/transactions')
  @ApiOperation({ summary: '获取交易流水' })
  @ApiParam({ name: 'accountSequence', description: '账户序号' })
  @ApiQuery({ name: 'page', required: false, type: Number })
  @ApiQuery({ name: 'pageSize', required: false, type: Number })
  @ApiResponse({ status: 200, description: '交易流水列表' })
  async getTransactions(
    @Param('accountSequence') accountSequence: string,
    @Query('page') page?: number,
    @Query('pageSize') pageSize?: number,
  ) {
    return this.getAccountQuery.getTransactions(
      accountSequence,
      page ?? 1,
      pageSize ?? 50,
    );
  }

  @Post('accounts/:accountSequence/transfer-out')
  @ApiOperation({ summary: '从挖矿账户划出积分股（到交易账户）' })
  @ApiParam({ name: 'accountSequence', description: '账户序号' })
  @ApiResponse({ status: 200, description: '划出成功' })
  @ApiResponse({ status: 400, description: '余额不足或参数错误' })
  async transferOut(
    @Param('accountSequence') accountSequence: string,
    @Body() dto: TransferDto,
  ) {
    const amount = new Decimal(dto.amount);
    if (amount.lessThanOrEqualTo(0)) {
      throw new BadRequestException('Amount must be positive');
    }

    // 查找账户
    const account = await this.prisma.miningAccount.findUnique({
      where: { accountSequence },
    });

    if (!account) {
      throw new NotFoundException(`Account ${accountSequence} not found`);
    }

    // 检查余额
    if (new Decimal(account.availableBalance).lessThan(amount)) {
      throw new BadRequestException('Insufficient balance');
    }

    // 执行划转（使用事务）
    const txId = `TX${Date.now().toString(36)}${Math.random().toString(36).substring(2, 8)}`.toUpperCase();

    await this.prisma.$transaction(async (tx) => {
      // 扣减余额
      const newBalance = new Decimal(account.availableBalance).minus(amount);
      await tx.miningAccount.update({
        where: { accountSequence },
        data: { availableBalance: newBalance },
      });

      // 创建交易记录
      await tx.miningTransaction.create({
        data: {
          accountSequence,
          type: 'TRANSFER_OUT',
          amount: amount.negated(),
          balanceBefore: account.availableBalance,
          balanceAfter: newBalance,
          referenceId: dto.transferNo || txId,
          referenceType: 'TRADING_TRANSFER',
          memo: `划转到交易账户，金额: ${amount.toString()}`,
        },
      });
    });

    return {
      success: true,
      txId,
      message: 'Transfer out successful',
    };
  }

  @Post('accounts/:accountSequence/transfer-in')
  @ApiOperation({ summary: '划入积分股到挖矿账户（从交易账户）' })
  @ApiParam({ name: 'accountSequence', description: '账户序号' })
  @ApiResponse({ status: 200, description: '划入成功' })
  @ApiResponse({ status: 400, description: '参数错误' })
  async transferIn(
    @Param('accountSequence') accountSequence: string,
    @Body() dto: TransferDto,
  ) {
    const amount = new Decimal(dto.amount);
    if (amount.lessThanOrEqualTo(0)) {
      throw new BadRequestException('Amount must be positive');
    }

    const txId = `TX${Date.now().toString(36)}${Math.random().toString(36).substring(2, 8)}`.toUpperCase();

    await this.prisma.$transaction(async (tx) => {
      // 查找或创建账户
      let account = await tx.miningAccount.findUnique({
        where: { accountSequence },
      });

      if (!account) {
        // 创建账户
        account = await tx.miningAccount.create({
          data: {
            accountSequence,
            totalMined: new Decimal(0),
            availableBalance: new Decimal(0),
            frozenBalance: new Decimal(0),
            totalContribution: new Decimal(0),
          },
        });
      }

      // 增加余额
      const newBalance = new Decimal(account.availableBalance).plus(amount);
      await tx.miningAccount.update({
        where: { accountSequence },
        data: { availableBalance: newBalance },
      });

      // 创建交易记录
      await tx.miningTransaction.create({
        data: {
          accountSequence,
          type: 'TRANSFER_IN',
          amount,
          balanceBefore: account.availableBalance,
          balanceAfter: newBalance,
          referenceId: dto.transferNo || txId,
          referenceType: 'TRADING_TRANSFER',
          memo: `从交易账户划入，金额: ${amount.toString()}`,
        },
      });
    });

    return {
      success: true,
      txId,
      message: 'Transfer in successful',
    };
  }
}
