import { Injectable, Logger, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../../common/prisma.service';
import { Currency } from '@prisma/client';

@Injectable()
export class CurrencyService {
  private readonly logger = new Logger(CurrencyService.name);

  constructor(private readonly prisma: PrismaService) {}

  async convertAmount(
    amountMinor: number,
    fromCurrency: Currency,
    toCurrency: Currency,
  ): Promise<number> {
    if (fromCurrency === toCurrency) {
      return amountMinor;
    }

    const rate = await this.getExchangeRate(fromCurrency, toCurrency);
    return Math.round(amountMinor * rate);
  }

  async getExchangeRate(
    fromCurrency: Currency,
    toCurrency: Currency,
  ): Promise<number> {
    const exchangeRate = await this.prisma.currencyExchangeRate.findFirst({
      where: {
        fromCurrency,
        toCurrency,
      },
      orderBy: {
        effectiveDate: 'desc',
      },
    });

    if (!exchangeRate) {
      this.logger.warn(
        `No exchange rate found for ${fromCurrency} to ${toCurrency}, using 1.0`,
      );
      return 1.0;
    }

    return Number(exchangeRate.rate);
  }

  async syncExchangeRates(): Promise<void> {
    this.logger.log('Syncing exchange rates from external provider');

    const today = this.todayUtc();
    const rates = [
      { from: 'ETB', to: 'ETB', rate: 1.0 },
      { from: 'ETB', to: 'DJF', rate: 3.25 },
      { from: 'ETB', to: 'USD', rate: 0.018 },
      { from: 'DJF', to: 'ETB', rate: 0.3077 },
      { from: 'USD', to: 'ETB', rate: 55.56 },
    ];

    for (const { from, to, rate } of rates) {
      await this.upsertRate(from as Currency, to as Currency, rate, today, 'EXTERNAL_API');
    }

    this.logger.log('Exchange rates synced successfully');
  }

  async listRates() {
    return this.prisma.currencyExchangeRate.findMany({
      orderBy: [{ fromCurrency: 'asc' }, { toCurrency: 'asc' }, { effectiveDate: 'desc' }],
    });
  }

  async upsertRate(
    fromCurrency: Currency,
    toCurrency: Currency,
    rate: number,
    effectiveDate?: Date,
    source = 'MANUAL',
  ) {
    const date = effectiveDate ?? this.todayUtc();
    return this.prisma.currencyExchangeRate.upsert({
      where: { fromCurrency_toCurrency_effectiveDate: { fromCurrency, toCurrency, effectiveDate: date } },
      update: { rate, source },
      create: { fromCurrency, toCurrency, rate, effectiveDate: date, source },
    });
  }

  async updateRateById(id: string, rate: number, source = 'MANUAL') {
    const existing = await this.prisma.currencyExchangeRate.findUnique({ where: { id } });
    if (!existing) throw new NotFoundException('Exchange rate not found');
    return this.prisma.currencyExchangeRate.update({ where: { id }, data: { rate, source } });
  }

  async deleteRate(id: string) {
    return this.prisma.currencyExchangeRate.delete({ where: { id } });
  }

  /** Returns midnight UTC for today — used as the date-only key for upserts. */
  private todayUtc(): Date {
    const d = new Date();
    d.setUTCHours(0, 0, 0, 0);
    return d;
  }
}
