/**
 * Accounting Service
 *
 * Replaces: DoAcount, UnDoAcount from TAmzServerImpl
 * Posts/unposts accounting entries (daily_tr) to ledger (gnledger)
 *
 * Original logic: For each row, ytd_db+=curms, ytd_cr+=curds, dtd_db+=curmd, dtd_cr+=curdd.
 * db_cr=1 (debit): lst_db=curms. db_cr=2 (credit): lst_cr=curds.
 */
import { Injectable, BadRequestException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';

@Injectable()
export class AccountingService {
  constructor(private prisma: PrismaService) {}

  private isDebit(dbCr: string | null): boolean {
    return dbCr === '1' || dbCr === 'D' || dbCr === 'd';
  }

  /**
   * DoAcount(N, kind, ref) - Post accounting entry to ledger
   */
  async doAcount(n: number, kind: number, ref: number): Promise<{ success: boolean }> {
    const rows = await this.prisma.dailyTr.findMany({
      where: { kind, ref, tranNo: n, tranSq: { not: 99000 } },
      orderBy: [{ tranSq: 'asc' }],
    });

    if (rows.length === 0) {
      throw new BadRequestException(`No daily entries for kind=${kind}, ref=${ref}, tran_no=${n}`);
    }

    for (const row of rows) {
      const actNo = row.dailyActNo;
      if (!actNo) {
        throw new BadRequestException(`Missing daily_act_no in entry tran_sq=${row.tranSq}`);
      }

      const curms = row.curMs ?? 0;
      const curds = row.curDs ?? 0;
      const curmd = row.curMd ?? 0;
      const curdd = row.curDd ?? 0;
      const debit = this.isDebit(row.dbCr);

      await this.prisma.$executeRawUnsafe(
        `UPDATE gnledger SET coun_trall = coun_trall + 1, ytd_db = ytd_db + ?, ytd_cr = ytd_cr + ?, dtd_db = dtd_db + ?, dtd_cr = dtd_cr + ? WHERE act_no = ?`,
        curms,
        curds,
        curmd,
        curdd,
        actNo,
      );

      if (debit) {
        await this.prisma.$executeRawUnsafe(
          `UPDATE gnledger SET lst_db = ? WHERE act_no = ?`,
          curms,
          actNo,
        );
      } else {
        await this.prisma.$executeRawUnsafe(
          `UPDATE gnledger SET lst_cr = ? WHERE act_no = ?`,
          curds,
          actNo,
        );
      }
    }

    return { success: true };
  }

  /**
   * UnDoAcount(N, kind, ref) - Unpost accounting entry from ledger
   */
  async unDoAcount(n: number, kind: number, ref: number): Promise<{ success: boolean }> {
    const rows = await this.prisma.dailyTr.findMany({
      where: { kind, ref, tranNo: n, tranSq: { not: 99000 } },
      orderBy: [{ tranSq: 'asc' }],
    });

    if (rows.length === 0) {
      throw new BadRequestException(`No daily entries for kind=${kind}, ref=${ref}, tran_no=${n}`);
    }

    for (const row of rows) {
      const actNo = row.dailyActNo;
      if (!actNo) continue;

      const curms = row.curMs ?? 0;
      const curds = row.curDs ?? 0;
      const curmd = row.curMd ?? 0;
      const curdd = row.curDd ?? 0;

      await this.prisma.$executeRawUnsafe(
        `UPDATE gnledger SET coun_trall = coun_trall - 1, ytd_db = ytd_db - ?, ytd_cr = ytd_cr - ?, dtd_db = dtd_db - ?, dtd_cr = dtd_cr - ? WHERE act_no = ?`,
        curms,
        curds,
        curmd,
        curdd,
        actNo,
      );

      const debit = this.isDebit(row.dbCr);
      if (debit) {
        await this.prisma.$executeRawUnsafe(
          `UPDATE gnledger SET lst_db = lst_db - ? WHERE act_no = ?`,
          curms,
          actNo,
        );
      } else {
        await this.prisma.$executeRawUnsafe(
          `UPDATE gnledger SET lst_cr = lst_cr - ? WHERE act_no = ?`,
          curds,
          actNo,
        );
      }
    }

    return { success: true };
  }
}
