<?php
declare(strict_types=1);

namespace App\Modules\Accounting\Services;

use App\Core\App;

class BudgetService
{
    public static function getVarianceReport(int $fiscalYearId, ?string $fromPeriod = null, ?string $toPeriod = null): array
    {
        $db = App::getInstance()->db();

        $params = [$fiscalYearId];
        $periodFilter = '';

        if ($fromPeriod && $toPeriod) {
            $periodFilter = " AND ab.period BETWEEN ? AND ?";
            $params[] = $fromPeriod;
            $params[] = $toPeriod;
        }

        $budgets = $db->select("
            SELECT
                ab.account_id,
                coa.account_code AS account_code,
                coa.name_ar AS account_name,
                coa.account_type,
                SUM(ab.budgeted_amount) AS total_budget
            FROM account_budgets ab
            JOIN chart_of_accounts coa ON coa.id = ab.account_id
            WHERE ab.fiscal_year_id = ?
            {$periodFilter}
            GROUP BY ab.account_id, coa.account_code, coa.name_ar, coa.account_type
            ORDER BY coa.account_code
        ", $params);

        $fy = $db->selectOne("SELECT start_date, end_date FROM fiscal_years WHERE id = ?", [$fiscalYearId]);
        if (!$fy) {
            return [];
        }

        $actualParams = [$fiscalYearId];
        $actualPeriodFilter = '';
        if ($fromPeriod && $toPeriod) {
            $actualPeriodFilter = " AND je.entry_date BETWEEN ? AND ?";
            $actualParams[] = $fromPeriod . '-01';
            $actualParams[] = $toPeriod . '-31';
        }

        $actuals = $db->select("
            SELECT
                jel.account_id,
                SUM(jel.debit) AS total_debit,
                SUM(jel.credit) AS total_credit
            FROM journal_entry_lines jel
            JOIN journal_entries je ON je.id = jel.journal_entry_id
            WHERE je.fiscal_year_id = ?
              AND je.status = 'posted'
              {$actualPeriodFilter}
            GROUP BY jel.account_id
        ", $actualParams);

        $actualMap = [];
        foreach ($actuals as $a) {
            $actualMap[(int)$a['account_id']] = $a;
        }

        $report = [];
        foreach ($budgets as $b) {
            $accountId = (int)$b['account_id'];
            $actual = $actualMap[$accountId] ?? ['total_debit' => 0, 'total_credit' => 0];

            $debit = (float)$actual['total_debit'];
            $credit = (float)$actual['total_credit'];

            if (in_array($b['account_type'], ['expense', 'asset'])) {
                $actualAmount = $debit - $credit;
            } else {
                $actualAmount = $credit - $debit;
            }

            $budget = (float)$b['total_budget'];
            $variance = $budget - $actualAmount;
            $variancePct = $budget != 0 ? ($variance / $budget) * 100 : 0;

            $report[] = [
                'account_id'    => $accountId,
                'account_code'  => $b['account_code'],
                'account_name'  => $b['account_name'],
                'account_type'  => $b['account_type'],
                'budgeted'      => $budget,
                'actual'        => $actualAmount,
                'variance'      => $variance,
                'variance_pct'  => round($variancePct, 1),
            ];
        }

        return $report;
    }

    public static function getCostCenterVariance(int $fiscalYearId, int $costCenterId): array
    {
        $db = App::getInstance()->db();

        $budgets = $db->select("
            SELECT
                ccb.account_id,
                coa.account_code AS account_code,
                coa.name_ar AS account_name,
                coa.account_type,
                SUM(ccb.budgeted_amount) AS total_budget
            FROM cost_center_budgets ccb
            LEFT JOIN chart_of_accounts coa ON coa.id = ccb.account_id
            WHERE ccb.fiscal_year_id = ? AND ccb.cost_center_id = ?
            GROUP BY ccb.account_id, coa.account_code, coa.name_ar, coa.account_type
            ORDER BY coa.account_code
        ", [$fiscalYearId, $costCenterId]);

        $actuals = $db->select("
            SELECT
                jel.account_id,
                SUM(jel.debit) AS total_debit,
                SUM(jel.credit) AS total_credit
            FROM journal_entry_lines jel
            JOIN journal_entries je ON je.id = jel.journal_entry_id
            WHERE je.fiscal_year_id = ?
              AND je.status = 'posted'
              AND jel.cost_center_id = ?
            GROUP BY jel.account_id
        ", [$fiscalYearId, $costCenterId]);

        $actualMap = [];
        foreach ($actuals as $a) {
            $actualMap[(int)$a['account_id']] = $a;
        }

        $report = [];
        foreach ($budgets as $b) {
            $accountId = (int)($b['account_id'] ?? 0);
            $actual = $actualMap[$accountId] ?? ['total_debit' => 0, 'total_credit' => 0];

            $debit = (float)$actual['total_debit'];
            $credit = (float)$actual['total_credit'];
            $accountType = $b['account_type'] ?? 'expense';

            if (in_array($accountType, ['expense', 'asset'])) {
                $actualAmount = $debit - $credit;
            } else {
                $actualAmount = $credit - $debit;
            }

            $budget = (float)$b['total_budget'];
            $variance = $budget - $actualAmount;
            $variancePct = $budget != 0 ? ($variance / $budget) * 100 : 0;

            $report[] = [
                'account_id'    => $accountId,
                'account_code'  => $b['account_code'] ?? '—',
                'account_name'  => $b['account_name'] ?? 'إجمالي المركز',
                'account_type'  => $accountType,
                'budgeted'      => $budget,
                'actual'        => $actualAmount,
                'variance'      => $variance,
                'variance_pct'  => round($variancePct, 1),
            ];
        }

        return $report;
    }
}
