import { Injectable } from '@nestjs/common';
import { PrismaService } from '../database/prisma.service';
import { IVirtualAccountRepository } from '../../domain/repositories/virtual-account.repository.interface';
import { VirtualAccount } from '../../domain/entities/virtual-account.entity';
import { VirtualAccountType } from '../../domain/value-objects/virtual-account-type.enum';
import { Decimal } from '@prisma/client/runtime/library';

@Injectable()
export class VirtualAccountRepositoryImpl implements IVirtualAccountRepository {
  constructor(private readonly prisma: PrismaService) {}

  async save(account: VirtualAccount): Promise<void> {
    const data = {
      accountType: account.accountType,
      displayName: account.displayName,
      avatar: account.avatar,
      provinceCode: account.provinceCode,
      cityCode: account.cityCode,
      minScore: account.minScore,
      maxScore: account.maxScore,
      currentScore: account.currentScore,
      usdtBalance: new Decimal(account.usdtBalance),
      hashpowerBalance: new Decimal(account.hashpowerBalance),
      isActive: account.isActive,
    };

    if (account.id) {
      await this.prisma.virtualAccount.update({
        where: { id: account.id },
        data,
      });
    } else {
      const result = await this.prisma.virtualAccount.create({
        data,
      });
      account.setId(result.id);
    }
  }

  async saveAll(accounts: VirtualAccount[]): Promise<void> {
    await this.prisma.$transaction(
      accounts.map((account) =>
        this.prisma.virtualAccount.create({
          data: {
            accountType: account.accountType,
            displayName: account.displayName,
            avatar: account.avatar,
            provinceCode: account.provinceCode,
            cityCode: account.cityCode,
            minScore: account.minScore,
            maxScore: account.maxScore,
            currentScore: account.currentScore,
            usdtBalance: new Decimal(account.usdtBalance),
            hashpowerBalance: new Decimal(account.hashpowerBalance),
            isActive: account.isActive,
          },
        })
      )
    );
  }

  async findById(id: bigint): Promise<VirtualAccount | null> {
    const record = await this.prisma.virtualAccount.findUnique({
      where: { id },
    });

    if (!record) return null;
    return this.toDomain(record);
  }

  async findByType(type: VirtualAccountType): Promise<VirtualAccount[]> {
    const records = await this.prisma.virtualAccount.findMany({
      where: { accountType: type },
      orderBy: { createdAt: 'asc' },
    });

    return records.map((r) => this.toDomain(r));
  }

  async findActiveRankingVirtuals(limit: number): Promise<VirtualAccount[]> {
    const records = await this.prisma.virtualAccount.findMany({
      where: {
        accountType: VirtualAccountType.RANKING_VIRTUAL,
        isActive: true,
      },
      take: limit,
      orderBy: { createdAt: 'asc' },
    });

    return records.map((r) => this.toDomain(r));
  }

  async findByProvinceCode(provinceCode: string): Promise<VirtualAccount | null> {
    const record = await this.prisma.virtualAccount.findFirst({
      where: {
        accountType: VirtualAccountType.SYSTEM_PROVINCE,
        provinceCode,
      },
    });

    if (!record) return null;
    return this.toDomain(record);
  }

  async findByCityCode(cityCode: string): Promise<VirtualAccount | null> {
    const record = await this.prisma.virtualAccount.findFirst({
      where: {
        accountType: VirtualAccountType.SYSTEM_CITY,
        cityCode,
      },
    });

    if (!record) return null;
    return this.toDomain(record);
  }

  async findHeadquarters(): Promise<VirtualAccount | null> {
    const record = await this.prisma.virtualAccount.findFirst({
      where: { accountType: VirtualAccountType.HEADQUARTERS },
    });

    if (!record) return null;
    return this.toDomain(record);
  }

  async countByType(type: VirtualAccountType): Promise<number> {
    return this.prisma.virtualAccount.count({
      where: { accountType: type },
    });
  }

  async deleteById(id: bigint): Promise<void> {
    await this.prisma.virtualAccount.delete({
      where: { id },
    });
  }

  private toDomain(record: any): VirtualAccount {
    return VirtualAccount.reconstitute({
      id: record.id,
      accountType: record.accountType as VirtualAccountType,
      displayName: record.displayName,
      avatar: record.avatar,
      provinceCode: record.provinceCode,
      cityCode: record.cityCode,
      minScore: record.minScore,
      maxScore: record.maxScore,
      currentScore: record.currentScore,
      usdtBalance: Number(record.usdtBalance),
      hashpowerBalance: Number(record.hashpowerBalance),
      isActive: record.isActive,
      createdAt: record.createdAt,
    });
  }
}
