<?php

namespace Modules\Accounting\Controllers;

use App\Controllers\BaseController;
use App\Models\ChartOfAccountModel;
use App\Traits\ExportsReport;
use Modules\Accounting\Services\AccountingReportService;

class AccountingReportController extends BaseController
{
    use ExportsReport;

    protected AccountingReportService $service;
    protected ChartOfAccountModel $accounts;

    public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
    {
        parent::initController($request, $response, $logger);
        $this->service  = new AccountingReportService();
        $this->accounts = new ChartOfAccountModel();
    }

    public function index()
    {
        return view('Modules\Accounting\Views\reports\index', array_merge($this->baseViewData(), [
            'title' => 'Financial Reports',
        ]));
    }

    public function trialBalance()
    {
        $filters = $this->service->resolveFilters($this->request->getGet() ?? []);
        $report  = $this->service->trialBalance($filters);

        $rows = array_map(static fn ($row) => [
            $row['code'] ?? '',
            $row['name'] ?? '',
            $row['type'] ?? '',
            number_format((float) ($row['debit'] ?? 0), 2),
            number_format((float) ($row['credit'] ?? 0), 2),
        ], $report['rows'] ?? []);
        $rows[] = ['', 'TOTAL', '', number_format((float) ($report['total_debit'] ?? 0), 2), number_format((float) ($report['total_credit'] ?? 0), 2)];

        if ($export = $this->exportTable(
            'trial_balance',
            'Trial Balance',
            ['Code', 'Account', 'Type', 'Debit', 'Credit'],
            $rows,
            $filters['date_from'] . ' to ' . $filters['date_to']
        )) {
            return $export;
        }

        return view('Modules\Accounting\Views\reports\trial_balance', array_merge($this->baseViewData(), [
            'title'   => 'Trial Balance',
            'filters' => $filters,
            'report'  => $report,
        ]));
    }

    public function generalLedger()
    {
        $filters = $this->service->resolveFilters($this->request->getGet() ?? []);
        $report  = $this->service->generalLedger($filters);

        $rows = [];
        foreach ($report['accounts'] ?? [] as $account) {
            foreach ($account['lines'] ?? [] as $line) {
                $rows[] = [
                    $account['account_code'] ?? '',
                    $account['account_name'] ?? '',
                    $line['entry_date'] ?? '',
                    $line['number'] ?? '',
                    $line['reference'] ?? '',
                    $line['description'] ?? '',
                    number_format((float) ($line['debit'] ?? 0), 2),
                    number_format((float) ($line['credit'] ?? 0), 2),
                    number_format((float) ($line['balance'] ?? 0), 2),
                ];
            }
        }

        if ($export = $this->exportTable(
            'general_ledger',
            'General Ledger',
            ['Account Code', 'Account', 'Date', 'Journal', 'Reference', 'Description', 'Debit', 'Credit', 'Balance'],
            $rows,
            $filters['date_from'] . ' to ' . $filters['date_to']
        )) {
            return $export;
        }

        return view('Modules\Accounting\Views\reports\general_ledger', array_merge($this->baseViewData(), [
            'title'    => 'General Ledger',
            'filters'  => $filters,
            'report'   => $report,
            'accounts' => $this->accounts->getActivePostable(),
        ]));
    }

    public function profitAndLoss()
    {
        $filters = $this->service->resolveFilters($this->request->getGet() ?? []);
        $report  = $this->service->profitAndLoss($filters);

        $revenueRows = array_map(static fn ($row) => [
            $row['code'] ?? '',
            $row['name'] ?? '',
            number_format((float) ($row['amount'] ?? 0), 2),
        ], $report['revenues'] ?? []);
        $revenueRows[] = ['', 'Total Revenue', number_format((float) ($report['total_revenue'] ?? 0), 2)];

        $expenseRows = array_map(static fn ($row) => [
            $row['code'] ?? '',
            $row['name'] ?? '',
            number_format((float) ($row['amount'] ?? 0), 2),
        ], $report['expenses'] ?? []);
        $expenseRows[] = ['', 'Total Expenses', number_format((float) ($report['total_expense'] ?? 0), 2)];
        $expenseRows[] = ['', 'Net Income', number_format((float) ($report['net_income'] ?? 0), 2)];

        if ($export = $this->exportSections(
            'profit_and_loss',
            'Profit and Loss',
            [
                ['title' => 'Revenue', 'headers' => ['Code', 'Account', 'Amount'], 'rows' => $revenueRows],
                ['title' => 'Expenses', 'headers' => ['Code', 'Account', 'Amount'], 'rows' => $expenseRows],
            ],
            $filters['date_from'] . ' to ' . $filters['date_to']
        )) {
            return $export;
        }

        return view('Modules\Accounting\Views\reports\profit_and_loss', array_merge($this->baseViewData(), [
            'title'   => 'Profit & Loss',
            'filters' => $filters,
            'report'  => $report,
        ]));
    }

    public function balanceSheet()
    {
        $filters = $this->service->resolveFilters($this->request->getGet() ?? []);
        $report  = $this->service->balanceSheet($filters);

        $mapRows = static function (array $items): array {
            return array_map(static fn ($row) => [
                $row['code'] ?? '',
                $row['name'] ?? '',
                number_format((float) ($row['amount'] ?? 0), 2),
            ], $items);
        };

        $assetRows = $mapRows($report['assets'] ?? []);
        $assetRows[] = ['', 'Total Assets', number_format((float) ($report['total_assets'] ?? 0), 2)];

        $liabRows = $mapRows($report['liabilities'] ?? []);
        $liabRows[] = ['', 'Total Liabilities', number_format((float) ($report['total_liabilities'] ?? 0), 2)];

        $equityRows = $mapRows($report['equity'] ?? []);
        $equityRows[] = ['', 'Net Income', number_format((float) ($report['net_income'] ?? 0), 2)];
        $equityRows[] = ['', 'Total Equity', number_format((float) ($report['total_equity_with_earnings'] ?? 0), 2)];

        if ($export = $this->exportSections(
            'balance_sheet',
            'Balance Sheet',
            [
                ['title' => 'Assets', 'headers' => ['Code', 'Account', 'Amount'], 'rows' => $assetRows],
                ['title' => 'Liabilities', 'headers' => ['Code', 'Account', 'Amount'], 'rows' => $liabRows],
                ['title' => 'Equity', 'headers' => ['Code', 'Account', 'Amount'], 'rows' => $equityRows],
            ],
            'As of ' . ($report['as_of'] ?? $filters['date_to'])
        )) {
            return $export;
        }

        return view('Modules\Accounting\Views\reports\balance_sheet', array_merge($this->baseViewData(), [
            'title'   => 'Balance Sheet',
            'filters' => $filters,
            'report'  => $report,
        ]));
    }

    public function cashFlow()
    {
        $filters = $this->service->resolveFilters($this->request->getGet() ?? []);
        $report  = $this->service->cashFlow($filters);

        $summaryRows = [
            ['Opening Cash', number_format((float) ($report['opening_cash'] ?? 0), 2)],
            ['Operating', number_format((float) ($report['operating']['net'] ?? 0), 2)],
            ['Investing', number_format((float) ($report['investing']['net'] ?? 0), 2)],
            ['Financing', number_format((float) ($report['financing']['net'] ?? 0), 2)],
            ['Closing Cash', number_format((float) ($report['closing_cash'] ?? 0), 2)],
        ];

        $detailMap = static function (array $section): array {
            return array_map(static fn ($row) => [
                $row['entry_date'] ?? '',
                $row['number'] ?? '',
                $row['counterpart'] ?? '',
                $row['description'] ?? '',
                number_format((float) ($row['amount'] ?? 0), 2),
            ], $section['rows'] ?? []);
        };

        if ($export = $this->exportSections(
            'cash_flow',
            'Cash Flow',
            [
                ['title' => 'Summary', 'headers' => ['Item', 'Amount'], 'rows' => $summaryRows],
                ['title' => 'Operating', 'headers' => ['Date', 'Journal', 'Counterpart', 'Description', 'Cash Impact'], 'rows' => $detailMap($report['operating'] ?? [])],
                ['title' => 'Investing', 'headers' => ['Date', 'Journal', 'Counterpart', 'Description', 'Cash Impact'], 'rows' => $detailMap($report['investing'] ?? [])],
                ['title' => 'Financing', 'headers' => ['Date', 'Journal', 'Counterpart', 'Description', 'Cash Impact'], 'rows' => $detailMap($report['financing'] ?? [])],
            ],
            $filters['date_from'] . ' to ' . $filters['date_to']
        )) {
            return $export;
        }

        return view('Modules\Accounting\Views\reports\cash_flow', array_merge($this->baseViewData(), [
            'title'   => 'Cash Flow',
            'filters' => $filters,
            'report'  => $report,
        ]));
    }
}
