/**
 * FinancialReportsService - Servicio de Reportes Financieros
 *
 * Generación de estados financieros y reportes contables.
 *
 * @module Finance
 */

import { DataSource, Repository, IsNull } from 'typeorm';
import {
  ChartOfAccounts,
  AccountType,
  AccountingEntryLine,
  AccountPayable,
  AccountReceivable,
  BankAccount,
} from '../entities';

interface ServiceContext {
  tenantId: string;
  userId?: string;
}

interface BalanceSheetAccount {
  accountId: string;
  accountCode: string;
  accountName: string;
  level: number;
  balance: number;
  children?: BalanceSheetAccount[];
}

interface BalanceSheet {
  asOfDate: Date;
  assets: {
    current: BalanceSheetAccount[];
    nonCurrent: BalanceSheetAccount[];
    totalCurrent: number;
    totalNonCurrent: number;
    total: number;
  };
  liabilities: {
    current: BalanceSheetAccount[];
    nonCurrent: BalanceSheetAccount[];
    totalCurrent: number;
    totalNonCurrent: number;
    total: number;
  };
  equity: {
    accounts: BalanceSheetAccount[];
    total: number;
  };
  totalLiabilitiesAndEquity: number;
  isBalanced: boolean;
}

interface IncomeStatementLine {
  accountId: string;
  accountCode: string;
  accountName: string;
  level: number;
  amount: number;
  children?: IncomeStatementLine[];
}

interface IncomeStatement {
  periodStart: Date;
  periodEnd: Date;
  revenue: {
    lines: IncomeStatementLine[];
    total: number;
  };
  costOfSales: {
    lines: IncomeStatementLine[];
    total: number;
  };
  grossProfit: number;
  operatingExpenses: {
    lines: IncomeStatementLine[];
    total: number;
  };
  operatingIncome: number;
  otherIncome: {
    lines: IncomeStatementLine[];
    total: number;
  };
  otherExpenses: {
    lines: IncomeStatementLine[];
    total: number;
  };
  incomeBeforeTax: number;
  taxExpense: number;
  netIncome: number;
}

interface CashFlowStatement {
  periodStart: Date;
  periodEnd: Date;
  operatingActivities: {
    netIncome: number;
    adjustments: { description: string; amount: number }[];
    changesInWorkingCapital: { description: string; amount: number }[];
    netCash: number;
  };
  investingActivities: {
    items: { description: string; amount: number }[];
    netCash: number;
  };
  financingActivities: {
    items: { description: string; amount: number }[];
    netCash: number;
  };
  netChangeInCash: number;
  beginningCash: number;
  endingCash: number;
}

export class FinancialReportsService {
  private accountRepository: Repository<ChartOfAccounts>;
  private lineRepository: Repository<AccountingEntryLine>;
  private apRepository: Repository<AccountPayable>;
  private arRepository: Repository<AccountReceivable>;
  private bankAccountRepository: Repository<BankAccount>;
  dataSource: DataSource;

  constructor(dataSource: DataSource) {
    this.dataSource = dataSource;
    this.accountRepository = dataSource.getRepository(ChartOfAccounts);
    this.lineRepository = dataSource.getRepository(AccountingEntryLine);
    this.apRepository = dataSource.getRepository(AccountPayable);
    this.arRepository = dataSource.getRepository(AccountReceivable);
    this.bankAccountRepository = dataSource.getRepository(BankAccount);
  }

  // ==================== BALANCE GENERAL ====================

  async generateBalanceSheet(
    ctx: ServiceContext,
    asOfDate: Date,
    options: { projectId?: string } = {}
  ): Promise<BalanceSheet> {
    const { projectId } = options;

    // Obtener todas las cuentas con saldos
    const accounts = await this.getAccountBalances(ctx, asOfDate, projectId);

    // Clasificar cuentas
    const assets = accounts.filter((acc) => acc.accountType === 'asset');
    const liabilities = accounts.filter((acc) => acc.accountType === 'liability');
    const equity = accounts.filter((acc) => acc.accountType === 'equity');

    // Construir árbol de activos
    const currentAssets = this.buildAccountTree(
      assets.filter((acc) => acc.isCurrentAccount)
    );
    const nonCurrentAssets = this.buildAccountTree(
      assets.filter((acc) => !acc.isCurrentAccount)
    );

    const totalCurrentAssets = currentAssets.reduce((sum, acc) => sum + acc.balance, 0);
    const totalNonCurrentAssets = nonCurrentAssets.reduce((sum, acc) => sum + acc.balance, 0);
    const totalAssets = totalCurrentAssets + totalNonCurrentAssets;

    // Construir árbol de pasivos
    const currentLiabilities = this.buildAccountTree(
      liabilities.filter((acc) => acc.isCurrentAccount)
    );
    const nonCurrentLiabilities = this.buildAccountTree(
      liabilities.filter((acc) => !acc.isCurrentAccount)
    );

    const totalCurrentLiabilities = currentLiabilities.reduce((sum, acc) => sum + acc.balance, 0);
    const totalNonCurrentLiabilities = nonCurrentLiabilities.reduce(
      (sum, acc) => sum + acc.balance,
      0
    );
    const totalLiabilities = totalCurrentLiabilities + totalNonCurrentLiabilities;

    // Construir árbol de capital
    const equityAccounts = this.buildAccountTree(equity);
    const totalEquity = equityAccounts.reduce((sum, acc) => sum + acc.balance, 0);

    const totalLiabilitiesAndEquity = totalLiabilities + totalEquity;
    const isBalanced = Math.abs(totalAssets - totalLiabilitiesAndEquity) < 0.01;

    return {
      asOfDate,
      assets: {
        current: currentAssets,
        nonCurrent: nonCurrentAssets,
        totalCurrent: totalCurrentAssets,
        totalNonCurrent: totalNonCurrentAssets,
        total: totalAssets,
      },
      liabilities: {
        current: currentLiabilities,
        nonCurrent: nonCurrentLiabilities,
        totalCurrent: totalCurrentLiabilities,
        totalNonCurrent: totalNonCurrentLiabilities,
        total: totalLiabilities,
      },
      equity: {
        accounts: equityAccounts,
        total: totalEquity,
      },
      totalLiabilitiesAndEquity,
      isBalanced,
    };
  }

  private async getAccountBalances(
    ctx: ServiceContext,
    asOfDate: Date,
    projectId?: string
  ): Promise<
    (ChartOfAccounts & { balance: number; isCurrentAccount: boolean })[]
  > {
    // Obtener todas las cuentas
    const accounts = await this.accountRepository.find({
      where: {
        tenantId: ctx.tenantId,
        deletedAt: IsNull(),
        allowsDirectPosting: true,
      },
      order: { code: 'ASC' },
    });

    // Obtener saldos de movimientos
    const queryBuilder = this.lineRepository
      .createQueryBuilder('line')
      .innerJoin('line.entry', 'entry')
      .select('line.accountId', 'accountId')
      .addSelect('SUM(line.debit)', 'totalDebit')
      .addSelect('SUM(line.credit)', 'totalCredit')
      .where('entry.tenantId = :tenantId', { tenantId: ctx.tenantId })
      .andWhere('entry.status = :status', { status: 'posted' })
      .andWhere('entry.entryDate <= :asOfDate', { asOfDate });

    if (projectId) {
      queryBuilder.andWhere('entry.projectId = :projectId', { projectId });
    }

    queryBuilder.groupBy('line.accountId');

    const balances = await queryBuilder.getRawMany();
    const balanceMap = new Map(
      balances.map((b) => [
        b.accountId,
        {
          debit: parseFloat(b.totalDebit) || 0,
          credit: parseFloat(b.totalCredit) || 0,
        },
      ])
    );

    return accounts.map((acc) => {
      const bal = balanceMap.get(acc.id) || { debit: 0, credit: 0 };
      let balance: number;

      // Calcular saldo según naturaleza
      if (acc.nature === 'debit') {
        balance = bal.debit - bal.credit;
      } else {
        balance = bal.credit - bal.debit;
      }

      // Determinar si es cuenta corriente (por código o metadata)
      const isCurrentAccount =
        acc.code.startsWith('1.1') || // Activo circulante
        acc.code.startsWith('2.1') || // Pasivo a corto plazo
        (acc.metadata as any)?.isCurrentAccount === true;

      return {
        ...acc,
        balance,
        isCurrentAccount,
      };
    });
  }

  private buildAccountTree(
    accounts: (ChartOfAccounts & { balance: number })[]
  ): BalanceSheetAccount[] {
    const rootAccounts = accounts.filter((acc) => !acc.parentId);

    const buildChildren = (
      parentId: string
    ): BalanceSheetAccount[] => {
      return accounts
        .filter((acc) => acc.parentId === parentId)
        .map((acc) => {
          const children = buildChildren(acc.id);
          const childBalance = children.reduce((sum, c) => sum + c.balance, 0);

          return {
            accountId: acc.id,
            accountCode: acc.code,
            accountName: acc.name,
            level: acc.level,
            balance: acc.balance + childBalance,
            children: children.length > 0 ? children : undefined,
          };
        });
    };

    return rootAccounts.map((acc) => {
      const children = buildChildren(acc.id);
      const childBalance = children.reduce((sum, c) => sum + c.balance, 0);

      return {
        accountId: acc.id,
        accountCode: acc.code,
        accountName: acc.name,
        level: acc.level,
        balance: acc.balance + childBalance,
        children: children.length > 0 ? children : undefined,
      };
    });
  }

  // ==================== ESTADO DE RESULTADOS ====================

  async generateIncomeStatement(
    ctx: ServiceContext,
    periodStart: Date,
    periodEnd: Date,
    options: { projectId?: string } = {}
  ): Promise<IncomeStatement> {
    const { projectId } = options;

    // Obtener movimientos del periodo
    const queryBuilder = this.lineRepository
      .createQueryBuilder('line')
      .innerJoin('line.entry', 'entry')
      .innerJoin(ChartOfAccounts, 'account', 'account.id = line.accountId')
      .select([
        'line.accountId as "accountId"',
        'line.accountCode as "accountCode"',
        'account.name as "accountName"',
        'account.accountType as "accountType"',
        'account.level as "level"',
        'account.parentId as "parentId"',
        'SUM(line.debit) as "totalDebit"',
        'SUM(line.credit) as "totalCredit"',
      ])
      .where('entry.tenantId = :tenantId', { tenantId: ctx.tenantId })
      .andWhere('entry.status = :status', { status: 'posted' })
      .andWhere('entry.entryDate BETWEEN :periodStart AND :periodEnd', {
        periodStart,
        periodEnd,
      })
      .andWhere('account.accountType IN (:...types)', { types: ['income', 'expense'] });

    if (projectId) {
      queryBuilder.andWhere('entry.projectId = :projectId', { projectId });
    }

    queryBuilder.groupBy(
      'line.accountId, line.accountCode, account.name, account.accountType, account.level, account.parentId'
    );

    const results = await queryBuilder.getRawMany();

    // Separar ingresos y gastos
    const incomeAccounts = results
      .filter((r) => r.accountType === 'income')
      .map((r) => ({
        accountId: r.accountId,
        accountCode: r.accountCode,
        accountName: r.accountName,
        level: r.level,
        parentId: r.parentId,
        amount: (parseFloat(r.totalCredit) || 0) - (parseFloat(r.totalDebit) || 0),
      }));

    const expenseAccounts = results
      .filter((r) => r.accountType === 'expense')
      .map((r) => ({
        accountId: r.accountId,
        accountCode: r.accountCode,
        accountName: r.accountName,
        level: r.level,
        parentId: r.parentId,
        amount: (parseFloat(r.totalDebit) || 0) - (parseFloat(r.totalCredit) || 0),
      }));

    // Clasificar ingresos
    const revenue = incomeAccounts.filter((acc) => acc.accountCode.startsWith('4.1'));
    const otherIncome = incomeAccounts.filter((acc) => !acc.accountCode.startsWith('4.1'));

    // Clasificar gastos
    const costOfSales = expenseAccounts.filter((acc) => acc.accountCode.startsWith('5.1'));
    const operatingExpenses = expenseAccounts.filter((acc) => acc.accountCode.startsWith('5.2'));
    const otherExpenses = expenseAccounts.filter(
      (acc) => !acc.accountCode.startsWith('5.1') && !acc.accountCode.startsWith('5.2')
    );

    // Calcular totales
    const totalRevenue = revenue.reduce((sum, acc) => sum + acc.amount, 0);
    const totalCostOfSales = costOfSales.reduce((sum, acc) => sum + acc.amount, 0);
    const grossProfit = totalRevenue - totalCostOfSales;

    const totalOperatingExpenses = operatingExpenses.reduce((sum, acc) => sum + acc.amount, 0);
    const operatingIncome = grossProfit - totalOperatingExpenses;

    const totalOtherIncome = otherIncome.reduce((sum, acc) => sum + acc.amount, 0);
    const totalOtherExpenses = otherExpenses.reduce((sum, acc) => sum + acc.amount, 0);

    const incomeBeforeTax = operatingIncome + totalOtherIncome - totalOtherExpenses;
    const taxExpense = 0; // TODO: Calcular ISR
    const netIncome = incomeBeforeTax - taxExpense;

    return {
      periodStart,
      periodEnd,
      revenue: {
        lines: this.buildIncomeTree(revenue),
        total: totalRevenue,
      },
      costOfSales: {
        lines: this.buildIncomeTree(costOfSales),
        total: totalCostOfSales,
      },
      grossProfit,
      operatingExpenses: {
        lines: this.buildIncomeTree(operatingExpenses),
        total: totalOperatingExpenses,
      },
      operatingIncome,
      otherIncome: {
        lines: this.buildIncomeTree(otherIncome),
        total: totalOtherIncome,
      },
      otherExpenses: {
        lines: this.buildIncomeTree(otherExpenses),
        total: totalOtherExpenses,
      },
      incomeBeforeTax,
      taxExpense,
      netIncome,
    };
  }

  private buildIncomeTree(
    accounts: {
      accountId: string;
      accountCode: string;
      accountName: string;
      level: number;
      parentId?: string;
      amount: number;
    }[]
  ): IncomeStatementLine[] {
    // Por simplicidad, retornamos lista plana ordenada por código
    return accounts
      .sort((a, b) => a.accountCode.localeCompare(b.accountCode))
      .map((acc) => ({
        accountId: acc.accountId,
        accountCode: acc.accountCode,
        accountName: acc.accountName,
        level: acc.level,
        amount: acc.amount,
      }));
  }

  // ==================== ESTADO DE FLUJO DE EFECTIVO ====================

  async generateCashFlowStatement(
    ctx: ServiceContext,
    periodStart: Date,
    periodEnd: Date,
    options: { projectId?: string } = {}
  ): Promise<CashFlowStatement> {
    const { projectId } = options;

    // Obtener estado de resultados para utilidad neta
    const incomeStatement = await this.generateIncomeStatement(
      ctx,
      periodStart,
      periodEnd,
      options
    );

    // Obtener saldos de cuentas bancarias
    const bankAccounts = await this.bankAccountRepository.find({
      where: {
        tenantId: ctx.tenantId,
        status: 'active',
        ...(projectId && { projectId }),
      },
    });

    const endingCash = bankAccounts.reduce(
      (sum, acc) => sum + Number(acc.currentBalance),
      0
    );

    // Simplificado - en producción se calcularían los cambios reales
    const operatingActivities = {
      netIncome: incomeStatement.netIncome,
      adjustments: [
        { description: 'Depreciación y amortización', amount: 0 },
        { description: 'Provisiones', amount: 0 },
      ],
      changesInWorkingCapital: [
        { description: 'Cambio en cuentas por cobrar', amount: 0 },
        { description: 'Cambio en inventarios', amount: 0 },
        { description: 'Cambio en cuentas por pagar', amount: 0 },
      ],
      netCash: incomeStatement.netIncome,
    };

    const investingActivities = {
      items: [
        { description: 'Compra de activos fijos', amount: 0 },
        { description: 'Venta de activos fijos', amount: 0 },
      ],
      netCash: 0,
    };

    const financingActivities = {
      items: [
        { description: 'Préstamos recibidos', amount: 0 },
        { description: 'Pagos de préstamos', amount: 0 },
        { description: 'Dividendos pagados', amount: 0 },
      ],
      netCash: 0,
    };

    const netChangeInCash =
      operatingActivities.netCash +
      investingActivities.netCash +
      financingActivities.netCash;

    const beginningCash = endingCash - netChangeInCash;

    return {
      periodStart,
      periodEnd,
      operatingActivities,
      investingActivities,
      financingActivities,
      netChangeInCash,
      beginningCash,
      endingCash,
    };
  }

  // ==================== BALANZA DE COMPROBACIÓN ====================

  async generateTrialBalance(
    ctx: ServiceContext,
    periodStart: Date,
    periodEnd: Date,
    options: { projectId?: string; includeZeroBalances?: boolean } = {}
  ): Promise<{
    accounts: {
      accountCode: string;
      accountName: string;
      accountType: AccountType;
      openingDebit: number;
      openingCredit: number;
      periodDebit: number;
      periodCredit: number;
      closingDebit: number;
      closingCredit: number;
    }[];
    totals: {
      openingDebit: number;
      openingCredit: number;
      periodDebit: number;
      periodCredit: number;
      closingDebit: number;
      closingCredit: number;
    };
  }> {
    const { projectId, includeZeroBalances = false } = options;

    // Obtener todas las cuentas
    const accounts = await this.accountRepository.find({
      where: {
        tenantId: ctx.tenantId,
        deletedAt: IsNull(),
        allowsDirectPosting: true,
      },
      order: { code: 'ASC' },
    });

    // Obtener saldos iniciales (movimientos antes del periodo)
    const openingQuery = this.lineRepository
      .createQueryBuilder('line')
      .innerJoin('line.entry', 'entry')
      .select('line.accountId', 'accountId')
      .addSelect('SUM(line.debit)', 'debit')
      .addSelect('SUM(line.credit)', 'credit')
      .where('entry.tenantId = :tenantId', { tenantId: ctx.tenantId })
      .andWhere('entry.status = :status', { status: 'posted' })
      .andWhere('entry.entryDate < :periodStart', { periodStart });

    if (projectId) {
      openingQuery.andWhere('entry.projectId = :projectId', { projectId });
    }

    openingQuery.groupBy('line.accountId');
    const openingBalances = await openingQuery.getRawMany();
    const openingMap = new Map(
      openingBalances.map((b) => [
        b.accountId,
        {
          debit: parseFloat(b.debit) || 0,
          credit: parseFloat(b.credit) || 0,
        },
      ])
    );

    // Obtener movimientos del periodo
    const periodQuery = this.lineRepository
      .createQueryBuilder('line')
      .innerJoin('line.entry', 'entry')
      .select('line.accountId', 'accountId')
      .addSelect('SUM(line.debit)', 'debit')
      .addSelect('SUM(line.credit)', 'credit')
      .where('entry.tenantId = :tenantId', { tenantId: ctx.tenantId })
      .andWhere('entry.status = :status', { status: 'posted' })
      .andWhere('entry.entryDate BETWEEN :periodStart AND :periodEnd', {
        periodStart,
        periodEnd,
      });

    if (projectId) {
      periodQuery.andWhere('entry.projectId = :projectId', { projectId });
    }

    periodQuery.groupBy('line.accountId');
    const periodMovements = await periodQuery.getRawMany();
    const periodMap = new Map(
      periodMovements.map((b) => [
        b.accountId,
        {
          debit: parseFloat(b.debit) || 0,
          credit: parseFloat(b.credit) || 0,
        },
      ])
    );

    // Construir balanza
    const trialBalance = accounts
      .map((acc) => {
        const opening = openingMap.get(acc.id) || { debit: 0, credit: 0 };
        const period = periodMap.get(acc.id) || { debit: 0, credit: 0 };

        // Calcular saldos según naturaleza
        let openingDebit = 0;
        let openingCredit = 0;
        const openingBalance = opening.debit - opening.credit;

        if (acc.nature === 'debit') {
          if (openingBalance >= 0) {
            openingDebit = openingBalance;
          } else {
            openingCredit = Math.abs(openingBalance);
          }
        } else {
          if (openingBalance <= 0) {
            openingCredit = Math.abs(openingBalance);
          } else {
            openingDebit = openingBalance;
          }
        }

        const closingBalance =
          openingBalance + period.debit - period.credit;
        let closingDebit = 0;
        let closingCredit = 0;

        if (acc.nature === 'debit') {
          if (closingBalance >= 0) {
            closingDebit = closingBalance;
          } else {
            closingCredit = Math.abs(closingBalance);
          }
        } else {
          if (closingBalance <= 0) {
            closingCredit = Math.abs(closingBalance);
          } else {
            closingDebit = closingBalance;
          }
        }

        return {
          accountCode: acc.code,
          accountName: acc.name,
          accountType: acc.accountType,
          openingDebit,
          openingCredit,
          periodDebit: period.debit,
          periodCredit: period.credit,
          closingDebit,
          closingCredit,
        };
      })
      .filter(
        (row) =>
          includeZeroBalances ||
          row.openingDebit !== 0 ||
          row.openingCredit !== 0 ||
          row.periodDebit !== 0 ||
          row.periodCredit !== 0
      );

    // Calcular totales
    const totals = trialBalance.reduce(
      (acc, row) => ({
        openingDebit: acc.openingDebit + row.openingDebit,
        openingCredit: acc.openingCredit + row.openingCredit,
        periodDebit: acc.periodDebit + row.periodDebit,
        periodCredit: acc.periodCredit + row.periodCredit,
        closingDebit: acc.closingDebit + row.closingDebit,
        closingCredit: acc.closingCredit + row.closingCredit,
      }),
      {
        openingDebit: 0,
        openingCredit: 0,
        periodDebit: 0,
        periodCredit: 0,
        closingDebit: 0,
        closingCredit: 0,
      }
    );

    return {
      accounts: trialBalance,
      totals,
    };
  }

  // ==================== REPORTES AUXILIARES ====================

  async generateAccountStatement(
    ctx: ServiceContext,
    accountId: string,
    periodStart: Date,
    periodEnd: Date
  ): Promise<{
    account: ChartOfAccounts;
    openingBalance: number;
    movements: {
      date: Date;
      entryNumber: string;
      reference?: string;
      description: string;
      debit: number;
      credit: number;
      balance: number;
    }[];
    closingBalance: number;
  }> {
    const account = await this.accountRepository.findOne({
      where: { id: accountId, tenantId: ctx.tenantId },
    });

    if (!account) {
      throw new Error('Cuenta no encontrada');
    }

    // Saldo de apertura
    const openingResult = await this.lineRepository
      .createQueryBuilder('line')
      .innerJoin('line.entry', 'entry')
      .select('SUM(line.debit)', 'debit')
      .addSelect('SUM(line.credit)', 'credit')
      .where('line.accountId = :accountId', { accountId })
      .andWhere('entry.tenantId = :tenantId', { tenantId: ctx.tenantId })
      .andWhere('entry.status = :status', { status: 'posted' })
      .andWhere('entry.entryDate < :periodStart', { periodStart })
      .getRawOne();

    const openingDebit = parseFloat(openingResult?.debit) || 0;
    const openingCredit = parseFloat(openingResult?.credit) || 0;
    let openingBalance =
      account.nature === 'debit'
        ? openingDebit - openingCredit
        : openingCredit - openingDebit;

    // Movimientos del periodo
    const lines = await this.lineRepository
      .createQueryBuilder('line')
      .innerJoinAndSelect('line.entry', 'entry')
      .where('line.accountId = :accountId', { accountId })
      .andWhere('entry.tenantId = :tenantId', { tenantId: ctx.tenantId })
      .andWhere('entry.status = :status', { status: 'posted' })
      .andWhere('entry.entryDate BETWEEN :periodStart AND :periodEnd', {
        periodStart,
        periodEnd,
      })
      .orderBy('entry.entryDate', 'ASC')
      .addOrderBy('entry.entryNumber', 'ASC')
      .getMany();

    let runningBalance = openingBalance;
    const movements = lines.map((line) => {
      if (account.nature === 'debit') {
        runningBalance += line.debit - line.credit;
      } else {
        runningBalance += line.credit - line.debit;
      }

      return {
        date: line.entry!.entryDate,
        entryNumber: line.entry!.entryNumber,
        reference: line.entry!.reference,
        description: line.description || line.entry!.description,
        debit: line.debit,
        credit: line.credit,
        balance: runningBalance,
      };
    });

    return {
      account,
      openingBalance,
      movements,
      closingBalance: runningBalance,
    };
  }

  async getFinancialSummary(ctx: ServiceContext): Promise<{
    totalAssets: number;
    totalLiabilities: number;
    totalEquity: number;
    currentRatio: number;
    cashPosition: number;
    accountsReceivable: number;
    accountsPayable: number;
    workingCapital: number;
  }> {
    const today = new Date();

    // Balance general simplificado
    const balanceSheet = await this.generateBalanceSheet(ctx, today);

    // Cuentas por cobrar
    const arResult = await this.arRepository
      .createQueryBuilder('ar')
      .select('SUM(ar.balanceAmount)', 'total')
      .where('ar.tenantId = :tenantId', { tenantId: ctx.tenantId })
      .andWhere('ar.status IN (:...statuses)', { statuses: ['pending', 'partial'] })
      .andWhere('ar.deletedAt IS NULL')
      .getRawOne();

    // Cuentas por pagar
    const apResult = await this.apRepository
      .createQueryBuilder('ap')
      .select('SUM(ap.balanceAmount)', 'total')
      .where('ap.tenantId = :tenantId', { tenantId: ctx.tenantId })
      .andWhere('ap.status IN (:...statuses)', { statuses: ['pending', 'partial'] })
      .andWhere('ap.deletedAt IS NULL')
      .getRawOne();

    // Efectivo
    const bankAccounts = await this.bankAccountRepository.find({
      where: {
        tenantId: ctx.tenantId,
        status: 'active',
      },
    });

    const cashPosition = bankAccounts.reduce(
      (sum, acc) => sum + Number(acc.currentBalance),
      0
    );

    const accountsReceivable = parseFloat(arResult?.total) || 0;
    const accountsPayable = parseFloat(apResult?.total) || 0;

    const currentAssets = balanceSheet.assets.totalCurrent;
    const currentLiabilities = balanceSheet.liabilities.totalCurrent;
    const currentRatio = currentLiabilities > 0 ? currentAssets / currentLiabilities : 0;
    const workingCapital = currentAssets - currentLiabilities;

    return {
      totalAssets: balanceSheet.assets.total,
      totalLiabilities: balanceSheet.liabilities.total,
      totalEquity: balanceSheet.equity.total,
      currentRatio: Math.round(currentRatio * 100) / 100,
      cashPosition,
      accountsReceivable,
      accountsPayable,
      workingCapital,
    };
  }
}
