import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
import { CreateTesCuentaDto } from '../dto/tes-cuenta.dto';
import { UpdateTesCuentaDto } from '../dto/tes-cuenta.dto';

@Injectable()
export class TesCuentasService {
  constructor(private readonly prisma: PrismaService) {}

  async create(dto: CreateTesCuentaDto, empresaId: string) {
    return this.prisma.tes_cuentas.create({
      data: {
        empresa_id: empresaId,
        nombre: dto.nombre,
        tipo: dto.tipo,
        moneda: dto.moneda,
        saldo_inicial: dto.saldo_inicial,
        saldo_actual: dto.saldo_inicial,
        cuenta_contable_id: dto.cuenta_contable_id ?? null,
        banco_id: dto.banco_id ?? null,
        numero_cuenta: dto.numero_cuenta ?? null,
        cbu_iban: dto.cbu_iban ?? null,
        titular: dto.titular ?? null,
        saldo_minimo_alerta: dto.saldo_minimo_alerta ?? null,
        activo: true,
      },
    });
  }

  /**
   * `soloActivas` es para los selectores de alta (registrar cheque, transferir,
   * crear regla): no tiene sentido crear algo nuevo contra una cuenta cerrada.
   * Los filtros de búsqueda y la administración piden la lista completa, porque
   * el historial de una cuenta cerrada se tiene que poder seguir consultando.
   */
  async findAll(empresaId: string, soloActivas = false) {
    return this.prisma.tes_cuentas.findMany({
      where: { empresa_id: empresaId, ...(soloActivas ? { activo: true } : {}) },
      orderBy: [{ activo: 'desc' }, { nombre: 'asc' }],
    });
  }

  async findOne(id: string, empresaId: string) {
    const cuenta = await this.prisma.tes_cuentas.findFirst({
      where: { id, empresa_id: empresaId },
    });
    if (!cuenta) {
      throw new NotFoundException(`Cuenta de tesorería ${id} no encontrada`);
    }
    return cuenta;
  }

  async update(id: string, dto: UpdateTesCuentaDto, empresaId: string) {
    await this.findOne(id, empresaId);
    return this.prisma.tes_cuentas.update({
      where: { id },
      data: {
        ...(dto.nombre !== undefined && { nombre: dto.nombre }),
        ...(dto.tipo !== undefined && { tipo: dto.tipo }),
        ...(dto.moneda !== undefined && { moneda: dto.moneda }),
        ...(dto.saldo_inicial !== undefined && { saldo_inicial: dto.saldo_inicial }),
        ...(dto.cuenta_contable_id !== undefined && { cuenta_contable_id: dto.cuenta_contable_id }),
        ...(dto.banco_id !== undefined && { banco_id: dto.banco_id }),
        ...(dto.numero_cuenta !== undefined && { numero_cuenta: dto.numero_cuenta }),
        ...(dto.cbu_iban !== undefined && { cbu_iban: dto.cbu_iban }),
        ...(dto.titular !== undefined && { titular: dto.titular }),
        ...(dto.saldo_minimo_alerta !== undefined && { saldo_minimo_alerta: dto.saldo_minimo_alerta }),
      },
    });
  }

  async toggleActivo(id: string, empresaId: string) {
    const cuenta = await this.findOne(id, empresaId);
    return this.prisma.tes_cuentas.update({
      where: { id },
      data: { activo: !cuenta.activo },
    });
  }

  async getSaldos(empresaId: string) {
    const cuentas = await this.prisma.tes_cuentas.findMany({
      where: { empresa_id: empresaId, activo: true },
      select: {
        id: true,
        nombre: true,
        tipo: true,
        moneda: true,
        saldo_actual: true,
        saldo_minimo_alerta: true,
      },
    });

    // Agrupar por moneda
    const porMoneda: Record<string, { moneda: string; total: number; cuentas: typeof cuentas }> = {};
    for (const cuenta of cuentas) {
      if (!porMoneda[cuenta.moneda]) {
        porMoneda[cuenta.moneda] = { moneda: cuenta.moneda, total: 0, cuentas: [] };
      }
      porMoneda[cuenta.moneda].total += Number(cuenta.saldo_actual ?? 0);
      porMoneda[cuenta.moneda].cuentas.push(cuenta);
    }

    return {
      por_moneda: Object.values(porMoneda),
      cuentas,
    };
  }
}
