/**
 * Ledger Service
 *
 * Replaces: LedgerProvider, Ledger from OracleDM
 * Table: gnledger (Chart of Accounts)
 */
import { Injectable, ConflictException, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import type { CreateLedgerDto } from './dto/create-ledger.dto';
import type { UpdateLedgerDto } from './dto/update-ledger.dto';

@Injectable()
export class LedgerService {
  constructor(private prisma: PrismaService) {}

  /**
   * Get all ledger accounts (chart of accounts)
   * Maps to: LedgerProvider data
   * Query: actUp - filter children of given parent (for tree)
   *        actCode - filter by account type (1=sub, 2=main)
   */
  async findAll(actUp?: string, actCode?: number) {
    const where: { actUp?: string; actCode?: number } = {};
    if (actUp !== undefined && actUp !== '') where.actUp = actUp;
    if (actCode !== undefined) where.actCode = actCode;
    return this.prisma.gnledger.findMany({
      where,
      orderBy: { actNo: 'asc' },
    });
  }

  /**
   * Get account by act_no
   * Maps to: GetAcount(ac) in OracleDM
   */
  async findByActNo(actNo: string, actCode?: number) {
    const where: { actNo: string; actCode?: number } = { actNo };
    if (actCode !== undefined) {
      where.actCode = actCode;
    }
    return this.prisma.gnledger.findFirst({
      where,
    });
  }

  /**
   * Create a new ledger account
   */
  async create(dto: CreateLedgerDto) {
    const existing = await this.prisma.gnledger.findUnique({
      where: { actNo: dto.actNo },
    });
    if (existing) {
      throw new ConflictException(`Account ${dto.actNo} already exists`);
    }
    return this.prisma.gnledger.create({
      data: {
        actNo: dto.actNo,
        actName: dto.actName ?? null,
        engName: dto.engName ?? null,
        actUp: dto.actUp ?? null,
        actCode: dto.actCode ?? 1,
        actBlnc: dto.actBlnc ?? 0,
        actKind: dto.actKind ?? 0,
        actGrop: dto.actGrop ?? 0,
        adrNm: dto.adrNm ?? null,
        adrCt: dto.adrCt ?? null,
        tlfNb: dto.tlfNb ?? null,
        faxNo: dto.faxNo ?? null,
        brcName: dto.brcName ?? null,
        mnyCode: dto.mnyCode ?? 0,
        brnchFlg: dto.brnchFlg ?? null,
        mndbFlg: dto.mndbFlg ?? null,
        klfFlg: dto.klfFlg ?? null,
        salrFlg: dto.salrFlg ?? null,
        exprFlg: dto.exprFlg ?? null,
      },
    });
  }

  /**
   * Update an existing ledger account
   */
  async update(actNo: string, dto: UpdateLedgerDto) {
    const existing = await this.prisma.gnledger.findUnique({
      where: { actNo },
    });
    if (!existing) {
      throw new NotFoundException(`Account ${actNo} not found`);
    }
    return this.prisma.gnledger.update({
      where: { actNo },
      data: {
        ...(dto.actName !== undefined && { actName: dto.actName }),
        ...(dto.engName !== undefined && { engName: dto.engName }),
        ...(dto.actUp !== undefined && { actUp: dto.actUp }),
        ...(dto.actCode !== undefined && { actCode: dto.actCode }),
        ...(dto.actBlnc !== undefined && { actBlnc: dto.actBlnc }),
        ...(dto.actKind !== undefined && { actKind: dto.actKind }),
        ...(dto.actGrop !== undefined && { actGrop: dto.actGrop }),
        ...(dto.adrNm !== undefined && { adrNm: dto.adrNm }),
        ...(dto.adrCt !== undefined && { adrCt: dto.adrCt }),
        ...(dto.tlfNb !== undefined && { tlfNb: dto.tlfNb }),
        ...(dto.faxNo !== undefined && { faxNo: dto.faxNo }),
        ...(dto.brcName !== undefined && { brcName: dto.brcName }),
        ...(dto.actGrop !== undefined && { actGrop: dto.actGrop }),
        ...(dto.mnyCode !== undefined && { mnyCode: dto.mnyCode }),
        ...(dto.brnchFlg !== undefined && { brnchFlg: dto.brnchFlg }),
        ...(dto.mndbFlg !== undefined && { mndbFlg: dto.mndbFlg }),
        ...(dto.klfFlg !== undefined && { klfFlg: dto.klfFlg }),
        ...(dto.salrFlg !== undefined && { salrFlg: dto.salrFlg }),
        ...(dto.exprFlg !== undefined && { exprFlg: dto.exprFlg }),
      },
    });
  }

  /**
   * Delete a ledger account
   * Block if counTrall > 0 (account has transactions)
   */
  async remove(actNo: string) {
    const existing = await this.prisma.gnledger.findUnique({
      where: { actNo },
    });
    if (!existing) {
      throw new NotFoundException(`Account ${actNo} not found`);
    }
    if (existing.counTrall > 0) {
      throw new ConflictException(
        `لا يمكن حذف الحساب لأنه يحتوي على حركات (عدد الحركات: ${existing.counTrall})`,
      );
    }
    const hasChildren = await this.prisma.gnledger.count({
      where: { actUp: actNo },
    });
    if (hasChildren > 0) {
      throw new ConflictException(
        `Cannot delete account ${actNo}: it has ${hasChildren} child account(s)`,
      );
    }
    return this.prisma.gnledger.delete({
      where: { actNo },
    });
  }
}
