import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { IPoolAccountCheckpointRepository } from '@/domain/repositories/pool-account-deposit.repository.interface';
import { ChainType, BlockNumber } from '@/domain/value-objects';
import { PoolAccountType } from '@/domain/enums';

@Injectable()
export class PoolAccountCheckpointRepositoryImpl implements IPoolAccountCheckpointRepository {
  constructor(private readonly prisma: PrismaService) {}

  async getLastScannedBlock(
    chainType: ChainType,
    poolType: PoolAccountType,
  ): Promise<BlockNumber | null> {
    const record = await this.prisma.poolAccountBlockCheckpoint.findUnique({
      where: {
        uk_pool_chain_pool: {
          chainType: chainType.toString(),
          poolType,
        },
      },
    });
    return record ? BlockNumber.create(record.lastScannedBlock) : null;
  }

  async updateCheckpoint(
    chainType: ChainType,
    poolType: PoolAccountType,
    blockNumber: BlockNumber,
  ): Promise<void> {
    await this.prisma.poolAccountBlockCheckpoint.upsert({
      where: {
        uk_pool_chain_pool: {
          chainType: chainType.toString(),
          poolType,
        },
      },
      update: {
        lastScannedBlock: blockNumber.value,
        lastScannedAt: new Date(),
        isHealthy: true,
        lastError: null,
      },
      create: {
        chainType: chainType.toString(),
        poolType,
        lastScannedBlock: blockNumber.value,
        lastScannedAt: new Date(),
        isHealthy: true,
      },
    });
  }

  async initializeIfNotExists(
    chainType: ChainType,
    poolType: PoolAccountType,
    blockNumber: BlockNumber,
  ): Promise<void> {
    const existing = await this.prisma.poolAccountBlockCheckpoint.findUnique({
      where: {
        uk_pool_chain_pool: {
          chainType: chainType.toString(),
          poolType,
        },
      },
    });

    if (!existing) {
      await this.prisma.poolAccountBlockCheckpoint.create({
        data: {
          chainType: chainType.toString(),
          poolType,
          lastScannedBlock: blockNumber.value,
          lastScannedAt: new Date(),
          isHealthy: true,
        },
      });
    }
  }

  async recordError(
    chainType: ChainType,
    poolType: PoolAccountType,
    error: string,
  ): Promise<void> {
    await this.prisma.poolAccountBlockCheckpoint.upsert({
      where: {
        uk_pool_chain_pool: {
          chainType: chainType.toString(),
          poolType,
        },
      },
      update: {
        isHealthy: false,
        lastError: error,
      },
      create: {
        chainType: chainType.toString(),
        poolType,
        lastScannedBlock: BigInt(0),
        lastScannedAt: new Date(),
        isHealthy: false,
        lastError: error,
      },
    });
  }

  async markHealthy(
    chainType: ChainType,
    poolType: PoolAccountType,
  ): Promise<void> {
    await this.prisma.poolAccountBlockCheckpoint.updateMany({
      where: {
        chainType: chainType.toString(),
        poolType,
      },
      data: {
        isHealthy: true,
        lastError: null,
      },
    });
  }
}
