import { Injectable, BadRequestException, Logger } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
import { ChargeCreditsDto } from './dto/charge-credits.dto';
import { UpdateSettingsDto } from './dto/update-settings.dto';

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

  constructor(private prisma: PrismaService) {}

  private async ensureCreditSettings(userId: number) {
    let settings = await this.prisma.creditSettings.findUnique({
      where: { userId },
    });
    if (!settings) {
      settings = await this.prisma.creditSettings.create({
        data: { userId, balance: 0 },
      });
    }
    return settings;
  }

  async getBalance(userId: number) {
    const settings = await this.ensureCreditSettings(userId);
    return {
      balance: settings.balance,
      autoCharge: settings.autoCharge,
      autoChargeThreshold: settings.autoChargeThreshold,
      autoChargeAmount: settings.autoChargeAmount,
      lowBalanceAlert: settings.lowBalanceAlert,
    };
  }

  async getTransactions(userId: number, query: { page?: number; limit?: number }) {
    const page = query.page || 1;
    const limit = query.limit || 20;
    const skip = (page - 1) * limit;
    const [transactions, total] = await Promise.all([
      this.prisma.creditTransaction.findMany({
        where: { userId },
        orderBy: { createdAt: 'desc' },
        skip,
        take: limit,
      }),
      this.prisma.creditTransaction.count({ where: { userId } }),
    ]);
    return {
      data: transactions,
      pagination: { page, limit, total, totalPages: Math.ceil(total / limit) },
    };
  }

  async charge(userId: number, dto: ChargeCreditsDto) {
    const settings = await this.ensureCreditSettings(userId);
    const newBalance = settings.balance + dto.amount;
    const result = await this.prisma.$transaction(async (tx) => {
      await tx.creditSettings.update({
        where: { userId },
        data: { balance: newBalance },
      });
      const transaction = await tx.creditTransaction.create({
        data: {
          userId,
          type: 'charge',
          description: 'Credit charge ' + dto.amount.toLocaleString() + ' won',
          amount: dto.amount,
          balanceAfter: newBalance,
        },
      });
      return { balance: newBalance, transaction };
    });
    return result;
  }

  async useCredits(
    userId: number,
    amount: number,
    description: string,
    refType?: string,
    refId?: number,
  ) {
    const settings = await this.ensureCreditSettings(userId);
    if (settings.balance < amount) {
      throw new BadRequestException('Insufficient credit balance');
    }
    const newBalance = settings.balance - amount;
    const result = await this.prisma.$transaction(async (tx) => {
      await tx.creditSettings.update({
        where: { userId },
        data: { balance: newBalance },
      });
      await tx.creditTransaction.create({
        data: {
          userId,
          type: 'use',
          description,
          amount: -amount,
          balanceAfter: newBalance,
          referenceType: refType || null,
          referenceId: refId || null,
        },
      });
      return { balance: newBalance };
    });
    return result;
  }

  async getSettings(userId: number) {
    const settings = await this.ensureCreditSettings(userId);
    return {
      balance: settings.balance,
      autoCharge: settings.autoCharge,
      autoChargeThreshold: settings.autoChargeThreshold,
      autoChargeAmount: settings.autoChargeAmount,
      lowBalanceAlert: settings.lowBalanceAlert,
    };
  }

  async updateSettings(userId: number, dto: UpdateSettingsDto) {
    await this.ensureCreditSettings(userId);
    const updated = await this.prisma.creditSettings.update({
      where: { userId },
      data: {
        ...(dto.autoCharge !== undefined && { autoCharge: dto.autoCharge }),
        ...(dto.autoChargeThreshold !== undefined && { autoChargeThreshold: dto.autoChargeThreshold }),
        ...(dto.autoChargeAmount !== undefined && { autoChargeAmount: dto.autoChargeAmount }),
        ...(dto.lowBalanceAlert !== undefined && { lowBalanceAlert: dto.lowBalanceAlert }),
      },
    });
    return {
      balance: updated.balance,
      autoCharge: updated.autoCharge,
      autoChargeThreshold: updated.autoChargeThreshold,
      autoChargeAmount: updated.autoChargeAmount,
      lowBalanceAlert: updated.lowBalanceAlert,
    };
  }

  async addBonus(userId: number, amount: number, description: string) {
    const settings = await this.ensureCreditSettings(userId);
    const newBalance = settings.balance + amount;
    const result = await this.prisma.$transaction(async (tx) => {
      await tx.creditSettings.update({
        where: { userId },
        data: { balance: newBalance },
      });
      await tx.creditTransaction.create({
        data: {
          userId,
          type: 'bonus',
          description,
          amount,
          balanceAfter: newBalance,
        },
      });
      return { balance: newBalance };
    });
    return result;
  }
}
