import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JsonRpcProvider, Contract } from 'ethers';
import { COUPON_ABI, COUPON_FACTORY_ABI } from '../../contracts/abis/coupon.abi';
import { CONTRACT_ADDRESSES } from '../../contracts/addresses';

@Injectable()
export class CouponService {
  private provider: JsonRpcProvider;
  private couponContract: Contract;
  private factoryContract: Contract;

  constructor(private config: ConfigService) {
    this.provider = new JsonRpcProvider(this.config.get('rpcUrl'));
    this.couponContract = new Contract(CONTRACT_ADDRESSES.coupon, COUPON_ABI, this.provider);
    this.factoryContract = new Contract(CONTRACT_ADDRESSES.couponFactory, COUPON_FACTORY_ABI, this.provider);
  }

  async getCouponDetail(tokenId: bigint) {
    const [config, resaleCount, owner, redeemed] = await Promise.all([
      this.couponContract.getConfig(tokenId),
      this.couponContract.getResaleCount(tokenId),
      this.couponContract.ownerOf(tokenId),
      this.couponContract.isRedeemed(tokenId),
    ]);

    return {
      tokenId: tokenId.toString(),
      owner,
      issuer: config.issuer,
      faceValue: config.faceValue.toString(),
      couponType: Number(config.couponType) === 0 ? 'utility' : 'security',
      expiryDate: new Date(Number(config.expiryDate) * 1000).toISOString(),
      maxResaleCount: Number(config.maxResaleCount),
      resaleCount: Number(resaleCount),
      transferable: config.transferable,
      redeemed,
      expired: Date.now() / 1000 > Number(config.expiryDate),
    };
  }

  async getBatchHolders(batchId: bigint) {
    const batchInfo = await this.factoryContract.getBatchInfo(batchId);
    const startTokenId = Number(batchInfo.startTokenId);
    const quantity = Number(batchInfo.quantity);
    const holders = new Map<string, number>();

    for (let i = 0; i < quantity && i < 1000; i++) {
      try {
        const owner = await this.couponContract.ownerOf(startTokenId + i);
        holders.set(owner, (holders.get(owner) || 0) + 1);
      } catch {
        // Token may be burned
      }
    }

    return {
      batchId: batchId.toString(),
      issuer: batchInfo.issuer,
      totalQuantity: quantity,
      uniqueHolders: holders.size,
      holders: Array.from(holders.entries()).map(([address, count]) => ({ address, count })),
    };
  }
}
