<?php

declare(strict_types=1);

namespace ApiModel\Tests\Integration\Http;

use ApiModel\Action\ReportAction;
use ApiModel\Infrastructure\Persistence\Repositories\PdoCompanyRepository;
use ApiModel\Infrastructure\Persistence\Repositories\PdoBranchRepository;
use ApiModel\Infrastructure\Persistence\Repositories\PdoUserAccessRepository;
use ApiModel\Infrastructure\Persistence\Repositories\PdoProfileRepository;
use ApiModel\Middleware\ApiErrorHandler;
use ApiModel\Middleware\CompanyContextMiddleware;
use ApiModel\Route\ReportRoutes;
use ApiModel\Service\FinancialReportService;
use ApiModel\Service\OrganizationService;
use Firebase\JWT\JWT;
use PDO;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ResponseInterface;
use Slim\App;
use Slim\Factory\AppFactory;
use Slim\Psr7\Factory\ServerRequestFactory;
use Slim\Psr7\Factory\StreamFactory;

final class ReportRoutesTest extends TestCase
{
    private PDO $pdo;
    private App $app;
    private string $adminToken;

    private const ADMIN_USER_ID = '11111111-1111-1111-1111-111111111111';
    private const ADMIN_ROLE_ID = '33333333-3333-3333-3333-333333333333';
    private const COMPANY_ID = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa';
    private const BRANCH_ID = 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb';
    private const CUSTOMER_ID = 'c1111111-1111-1111-1111-111111111111';
    private const VENDOR_ID = 'v1111111-1111-1111-1111-111111111111';

    private const CASH_ACCOUNT_ID = 'ca111111-1111-1111-1111-111111111111';
    private const RECEIVABLE_ACCOUNT_ID = 'ca222222-2222-2222-2222-222222222222';
    private const PAYABLE_ACCOUNT_ID = 'ca333333-3333-3333-3333-333333333333';
    private const CAPITAL_ACCOUNT_ID = 'ca444444-4444-4444-4444-444444444444';
    private const REVENUE_ACCOUNT_ID = 'ca555555-5555-5555-5555-555555555555';
    private const EXPENSE_ACCOUNT_ID = 'ca666666-6666-6666-6666-666666666666';

    protected function setUp(): void
    {
        parent::setUp();

        $this->pdo = new PDO('sqlite::memory:');
        $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

        $this->createSchema();
        $this->seedData();
        $this->configureEnv();

        $this->app = $this->buildApp();
        $this->adminToken = $this->issueToken(self::ADMIN_USER_ID, 'ADMINISTRADOR');
    }

    /** @return array<string, string> */
    private function companyHeaders(): array
    {
        return [
            'Authorization' => 'Bearer ' . $this->adminToken,
            'X-Company-Id' => self::COMPANY_ID,
            'X-Branch-Id' => self::BRANCH_ID,
        ];
    }

    public function testTrialBalance(): void
    {
        // Consultar Balanza de Comprobación
        $response = $this->request(
            'GET', 
            '/reports/trial-balance?start_date=2026-06-01&end_date=2026-06-30', 
            $this->companyHeaders()
        );

        $this->assertSame(200, $response->getStatusCode());
        $body = $this->decodeBody($response);

        // Deberían haber 6 cuentas registradas
        $this->assertCount(6, $body);

        // Verificar Caja (1105): debito=1000, credito=200, final_balance=800
        $cash = $this->findAccountInReport($body, '1105');
        $this->assertNotNull($cash);
        $this->assertEquals(1000.0, $cash['debit']);
        $this->assertEquals(200.0, $cash['credit']);
        $this->assertEquals(800.0, $cash['final_balance']);

        // Verificar Capital (3105): credit=1000, final_balance=1000 (credit nature)
        $capital = $this->findAccountInReport($body, '3105');
        $this->assertNotNull($capital);
        $this->assertEquals(0.0, $capital['debit']);
        $this->assertEquals(1000.0, $capital['credit']);
        $this->assertEquals(1000.0, $capital['final_balance']);
    }

    public function testBalanceSheet(): void
    {
        // Consultar Balance General
        $response = $this->request(
            'GET', 
            '/reports/balance-sheet?end_date=2026-06-22', 
            $this->companyHeaders()
        );

        $this->assertSame(200, $response->getStatusCode());
        $body = $this->decodeBody($response);

        $this->assertArrayHasKey('assets', $body);
        $this->assertArrayHasKey('liabilities', $body);
        $this->assertArrayHasKey('equity', $body);
        $this->assertArrayHasKey('totals', $body);

        $totals = $body['totals'];
        // Activo = Caja(800) + CxC(500) = 1300
        $this->assertEquals(1300.0, $totals['total_assets']);
        // Pasivo = 0
        $this->assertEquals(0.0, $totals['total_liabilities']);
        // Patrimonio = Capital(1000) + Utilidad del Ejercicio(300) = 1300
        $this->assertEquals(1300.0, $totals['total_equity']);
        // Utilidad neta = 300
        $this->assertEquals(300.0, $totals['net_income']);

        // Verificar que la cuenta de utilidad virtual 3605 fue inyectada en el patrimonio
        $netIncomeVirtualAcc = $this->findAccountInReport($body['equity'], '3605');
        $this->assertNotNull($netIncomeVirtualAcc);
        $this->assertEquals(300.0, $netIncomeVirtualAcc['balance']);
    }

    public function testProfitAndLoss(): void
    {
        // Consultar Estado de Resultados
        $response = $this->request(
            'GET', 
            '/reports/profit-and-loss?start_date=2026-06-01&end_date=2026-06-30', 
            $this->companyHeaders()
        );

        $this->assertSame(200, $response->getStatusCode());
        $body = $this->decodeBody($response);

        $this->assertArrayHasKey('income', $body);
        $this->assertArrayHasKey('expenses', $body);
        $this->assertArrayHasKey('totals', $body);

        $totals = $body['totals'];
        // Ingresos = 500
        $this->assertEquals(500.0, $totals['total_income']);
        // Gastos = 200
        $this->assertEquals(200.0, $totals['total_expense']);
        // Utilidad = 300
        $this->assertEquals(300.0, $totals['net_income']);
    }

    public function testArAgingReport(): void
    {
        // Consultar Antigüedad de Cuentas por Cobrar con fecha de referencia 2026-06-22
        $response = $this->request(
            'GET', 
            '/reports/ar-aging?reference_date=2026-06-22', 
            $this->companyHeaders()
        );

        $this->assertSame(200, $response->getStatusCode());
        $body = $this->decodeBody($response);

        $this->assertCount(1, $body);
        $row = $body[0];
        $this->assertSame('Cliente Ejemplo', $row['contact_name']);
        $this->assertEquals(500.0, $row['total_balance']);
        // Vence 2026-07-15, la referencia es 2026-06-22. Está al día (current)
        $this->assertEquals(500.0, $row['current']);
        $this->assertEquals(0.0, $row['bracket_1_30']);
    }

    public function testApAgingReport(): void
    {
        // Consultar Antigüedad de Cuentas por Pagar con fecha de referencia 2026-06-22
        $response = $this->request(
            'GET', 
            '/reports/ap-aging?reference_date=2026-06-22', 
            $this->companyHeaders()
        );

        $this->assertSame(200, $response->getStatusCode());
        $body = $this->decodeBody($response);

        $this->assertCount(1, $body);
        $row = $body[0];
        $this->assertSame('Proveedor Ejemplo', $row['contact_name']);
        $this->assertEquals(300.0, $row['total_balance']);
        // Vencía 2026-06-20, la referencia es 2026-06-22. Está vencido por 2 días (bracket 1-30)
        $this->assertEquals(0.0, $row['current']);
        $this->assertEquals(300.0, $row['bracket_1_30']);
    }

    public function testSalesBook(): void
    {
        // Seed a credit note and a debit note
        $this->pdo->prepare(
            'INSERT INTO sales_adjustments (id, company_id, branch_id, customer_id, adjustment_type, document_number, document_date, reference_invoice_id, receivable_account_id, discount_amount, tax_amount, subtotal, total, status)
             VALUES (?,?,?,?, "credit_note", "0001", "2026-06-16", "si1", ?, 0.0, 10.0, 100.0, 110.0, "posted")'
        )->execute(['sa1', self::COMPANY_ID, self::BRANCH_ID, self::CUSTOMER_ID, self::RECEIVABLE_ACCOUNT_ID]);

        $this->pdo->prepare(
            'INSERT INTO sales_adjustments (id, company_id, branch_id, customer_id, adjustment_type, document_number, document_date, reference_invoice_id, receivable_account_id, discount_amount, tax_amount, subtotal, total, status)
             VALUES (?,?,?,?, "debit_note", "0002", "2026-06-17", "si1", ?, 0.0, 5.0, 50.0, 55.0, "posted")'
        )->execute(['sa2', self::COMPANY_ID, self::BRANCH_ID, self::CUSTOMER_ID, self::RECEIVABLE_ACCOUNT_ID]);

        $response = $this->request(
            'GET', 
            '/reports/sales-book?start_date=2026-06-01&end_date=2026-06-30', 
            $this->companyHeaders()
        );

        $this->assertSame(200, $response->getStatusCode());
        $body = $this->decodeBody($response);

        // Deberían haber 3 registros (factura + nota de crédito + nota de débito)
        $this->assertCount(3, $body);

        // Registro 0: Invoice
        $this->assertSame('INV-001', $body[0]['invoice_number']);
        $this->assertEquals(500.0, $body[0]['total']);

        // Registro 1: Credit Note (negativa)
        $this->assertSame('NC-0001', $body[1]['invoice_number']);
        $this->assertEquals(-100.0, $body[1]['subtotal']);
        $this->assertEquals(-10.0, $body[1]['tax_amount']);
        $this->assertEquals(-110.0, $body[1]['total']);

        // Registro 2: Debit Note (positiva)
        $this->assertSame('ND-0002', $body[2]['invoice_number']);
        $this->assertEquals(50.0, $body[2]['subtotal']);
        $this->assertEquals(5.0, $body[2]['tax_amount']);
        $this->assertEquals(55.0, $body[2]['total']);
    }

    public function testPurchasesBook(): void
    {
        $response = $this->request(
            'GET', 
            '/reports/purchases-book?start_date=2026-06-01&end_date=2026-06-30', 
            $this->companyHeaders()
        );

        $this->assertSame(200, $response->getStatusCode());
        $body = $this->decodeBody($response);

        $this->assertCount(1, $body);
        $this->assertSame('BILL-001', $body[0]['bill_number']);
        $this->assertSame('Proveedor Ejemplo', $body[0]['vendor_name']);
        $this->assertEquals(300.0, $body[0]['total']);
    }

    private function findAccountInReport(array $accounts, string $code): ?array
    {
        foreach ($accounts as $acc) {
            if ($acc['code'] === $code) {
                return $acc;
            }
        }
        return null;
    }

    private function buildApp(): App
    {
        $app = AppFactory::create();

        $organizationService = new OrganizationService(
            new PdoCompanyRepository($this->pdo),
            new PdoBranchRepository($this->pdo),
            new PdoUserAccessRepository($this->pdo),
            new PdoProfileRepository($this->pdo),
        );

        $reportService = new FinancialReportService($this->pdo);
        $action = new ReportAction($reportService);
        $companyMiddleware = new CompanyContextMiddleware($organizationService);

        $app->group('', function ($g) use ($action): void {
            ReportRoutes::register($g, $action);
        });

        $app->addRoutingMiddleware();
        $app->add($companyMiddleware);
        $errorMiddleware = $app->addErrorMiddleware(false, true, true);
        $errorMiddleware->setDefaultErrorHandler(ApiErrorHandler::create($app->getResponseFactory()));

        return $app;
    }

    private function request(string $method, string $path, array $headers = []): ResponseInterface
    {
        $requestFactory = new ServerRequestFactory();
        $request = $requestFactory->createServerRequest($method, $path);
        foreach ($headers as $name => $value) {
            $request = $request->withHeader($name, $value);
        }

        return $this->app->handle($request);
    }

    /** @return array<string, mixed> */
    private function decodeBody(ResponseInterface $response): array
    {
        $raw = (string) $response->getBody();
        $data = json_decode($raw, true);

        return is_array($data) ? $data : [];
    }

    private function issueToken(string $userId, string $role): string
    {
        return JWT::encode([
            'sub' => $userId,
            'role' => $role,
            'lang' => 'es',
            'iat' => time(),
            'exp' => time() + 3600,
        ], (string) $_ENV['JWT_SECRET'], 'HS256');
    }

    private function createSchema(): void
    {
        $this->pdo->exec("ATTACH DATABASE ':memory:' AS auth");

        $this->pdo->exec(
            'CREATE TABLE auth.users (
                id TEXT PRIMARY KEY,
                name TEXT NOT NULL,
                email TEXT NOT NULL UNIQUE,
                password_hash TEXT NULL,
                language TEXT NOT NULL DEFAULT "es",
                is_active INTEGER NOT NULL DEFAULT 1
            )',
        );

        $this->pdo->exec(
            'CREATE TABLE auth.roles (
                id TEXT PRIMARY KEY,
                name_es TEXT NOT NULL UNIQUE,
                name_en TEXT NOT NULL UNIQUE,
                description_es TEXT,
                description_en TEXT,
                is_active INTEGER NOT NULL DEFAULT 1
            )',
        );

        $this->pdo->exec(
            'CREATE TABLE auth.role_user (
                role_id TEXT NOT NULL,
                user_id TEXT NOT NULL,
                PRIMARY KEY (role_id, user_id)
            )',
        );

        $this->pdo->exec(
            'CREATE TABLE companies (
                id TEXT PRIMARY KEY,
                legal_name TEXT NOT NULL,
                trade_name TEXT,
                tax_id TEXT NOT NULL UNIQUE,
                base_currency TEXT NOT NULL DEFAULT "USD",
                email TEXT,
                phone TEXT,
                address TEXT,
                is_active INTEGER NOT NULL DEFAULT 1,
                created_at TEXT DEFAULT CURRENT_TIMESTAMP,
                updated_at TEXT DEFAULT CURRENT_TIMESTAMP
            )',
        );

        $this->pdo->exec(
            'CREATE TABLE branches (
                id TEXT PRIMARY KEY,
                company_id TEXT NOT NULL,
                name TEXT NOT NULL,
                code TEXT,
                address TEXT,
                phone TEXT,
                is_main INTEGER NOT NULL DEFAULT 0,
                operating_currency TEXT NOT NULL DEFAULT "USD",
                is_active INTEGER NOT NULL DEFAULT 1,
                created_at TEXT DEFAULT CURRENT_TIMESTAMP,
                updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
                UNIQUE (company_id, code)
            )',
        );

        $this->pdo->exec(
            'CREATE TABLE user_access (
                id TEXT PRIMARY KEY,
                user_id TEXT NOT NULL,
                company_id TEXT NOT NULL,
                branch_id TEXT,
                can_manage INTEGER NOT NULL DEFAULT 0,
                is_default INTEGER NOT NULL DEFAULT 0,
                created_at TEXT DEFAULT CURRENT_TIMESTAMP,
                UNIQUE (user_id, company_id)
            )',
        );

        $this->pdo->exec(
            'CREATE TABLE contacts (
                id TEXT PRIMARY KEY,
                company_id TEXT NOT NULL,
                type TEXT NOT NULL,
                name TEXT NOT NULL,
                tax_id TEXT NULL,
                email TEXT NULL,
                phone TEXT NULL,
                address TEXT NULL,
                is_active INTEGER NOT NULL DEFAULT 1,
                created_at TEXT DEFAULT CURRENT_TIMESTAMP,
                updated_at TEXT DEFAULT CURRENT_TIMESTAMP
            )'
        );

        $this->pdo->exec(
            'CREATE TABLE chart_accounts (
                id TEXT PRIMARY KEY,
                company_id TEXT NOT NULL,
                parent_id TEXT NULL,
                code TEXT NOT NULL,
                name TEXT NOT NULL,
                account_type TEXT NOT NULL,
                is_header INTEGER NOT NULL DEFAULT 0,
                is_active INTEGER NOT NULL DEFAULT 1,
                created_at TEXT DEFAULT CURRENT_TIMESTAMP,
                updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
                UNIQUE (company_id, code)
            )',
        );

        $this->pdo->exec(
            'CREATE TABLE journal_entries (
                id TEXT PRIMARY KEY,
                company_id TEXT NOT NULL,
                branch_id TEXT NULL,
                entry_number TEXT NOT NULL,
                entry_date TEXT NOT NULL,
                description TEXT NULL,
                status TEXT NOT NULL DEFAULT "draft",
                operating_currency TEXT NOT NULL,
                functional_currency TEXT NOT NULL,
                exchange_rate REAL NOT NULL DEFAULT 1,
                created_by TEXT NULL,
                created_at TEXT DEFAULT CURRENT_TIMESTAMP,
                updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
                UNIQUE (company_id, entry_number)
            )',
        );

        $this->pdo->exec(
            'CREATE TABLE journal_lines (
                id TEXT PRIMARY KEY,
                journal_entry_id TEXT NOT NULL,
                chart_account_id TEXT NOT NULL,
                line_order INTEGER NOT NULL DEFAULT 0,
                description TEXT NULL,
                debit REAL NOT NULL DEFAULT 0,
                credit REAL NOT NULL DEFAULT 0,
                debit_functional REAL NOT NULL DEFAULT 0,
                credit_functional REAL NOT NULL DEFAULT 0
            )',
        );

        $this->pdo->exec(
            'CREATE TABLE sales_invoices (
                id TEXT PRIMARY KEY,
                company_id TEXT NOT NULL,
                branch_id TEXT NULL,
                customer_id TEXT NOT NULL,
                receivable_account_id TEXT NOT NULL,
                invoice_number TEXT NOT NULL,
                invoice_date TEXT NOT NULL,
                due_date TEXT NOT NULL,
                reference TEXT,
                subtotal REAL NOT NULL DEFAULT 0.0,
                discount_amount REAL NOT NULL DEFAULT 0.0,
                tax_amount REAL NOT NULL DEFAULT 0.0,
                currency_code TEXT NOT NULL DEFAULT "USD",
                exchange_rate REAL NOT NULL DEFAULT 1.0,
                total REAL NOT NULL DEFAULT 0.0,
                balance REAL NOT NULL DEFAULT 0.0,
                status TEXT NOT NULL DEFAULT "draft"
            )'
        );

        $this->pdo->exec(
            'CREATE TABLE purchases_bills (
                id TEXT PRIMARY KEY,
                company_id TEXT NOT NULL,
                branch_id TEXT NULL,
                vendor_id TEXT NOT NULL,
                payable_account_id TEXT NOT NULL,
                bill_number TEXT NOT NULL,
                bill_date TEXT NOT NULL,
                due_date TEXT NOT NULL,
                reference TEXT,
                subtotal REAL NOT NULL DEFAULT 0.0,
                discount_amount REAL NOT NULL DEFAULT 0.0,
                tax_amount REAL NOT NULL DEFAULT 0.0,
                currency_code TEXT NOT NULL DEFAULT "USD",
                exchange_rate REAL NOT NULL DEFAULT 1.0,
                total REAL NOT NULL DEFAULT 0.0,
                balance REAL NOT NULL DEFAULT 0.0,
                status TEXT NOT NULL DEFAULT "draft"
            )'
        );

        $this->pdo->exec(
            'CREATE TABLE sales_adjustments (
                id TEXT PRIMARY KEY,
                company_id TEXT NOT NULL,
                branch_id TEXT NULL,
                customer_id TEXT NOT NULL,
                adjustment_type TEXT NOT NULL,
                document_number TEXT NOT NULL,
                document_date TEXT NOT NULL,
                reference_invoice_id TEXT NULL,
                receivable_account_id TEXT NOT NULL,
                discount_amount REAL NOT NULL DEFAULT 0.0,
                tax_amount REAL NOT NULL DEFAULT 0.0,
                subtotal REAL NOT NULL DEFAULT 0.0,
                total REAL NOT NULL DEFAULT 0.0,
                status TEXT NOT NULL DEFAULT "draft"
            )'
        );
    }

    private function seedData(): void
    {
        $this->pdo->prepare(
            'INSERT INTO auth.users (id, name, email, password_hash, is_active) VALUES (?,?,?, "hash", 1)'
        )->execute([self::ADMIN_USER_ID, 'Admin User', 'admin@example.com']);

        $this->pdo->prepare(
            'INSERT INTO auth.roles (id, name_es, name_en) VALUES (?,?,?)'
        )->execute([self::ADMIN_ROLE_ID, 'ADMINISTRADOR', 'ADMINISTRATOR']);

        $this->pdo->prepare('INSERT INTO auth.role_user (role_id, user_id) VALUES (?,?)')
            ->execute([self::ADMIN_ROLE_ID, self::ADMIN_USER_ID]);

        $this->pdo->prepare(
            'INSERT INTO companies (id, legal_name, trade_name, tax_id, base_currency, is_active)
             VALUES (?,?,?,?,?,1)'
        )->execute([self::COMPANY_ID, 'Empresa Demo', 'Demo', '900111222-3', 'USD']);

        $this->pdo->prepare(
            'INSERT INTO branches (id, company_id, name, code, is_main, operating_currency, is_active)
             VALUES (?,?,?,?,1,?,1)'
        )->execute([self::BRANCH_ID, self::COMPANY_ID, 'Principal', 'MAIN', 'USD']);

        $this->pdo->prepare(
            'INSERT INTO user_access (id, user_id, company_id, branch_id, can_manage, is_default)
             VALUES (?,?,?,?,1,1)'
        )->execute(['dddddddd-dddd-dddd-dddd-dddddddddddd', self::ADMIN_USER_ID, self::COMPANY_ID, self::BRANCH_ID]);

        // Seed contact (customer and vendor)
        $this->pdo->prepare('INSERT INTO contacts (id, company_id, type, name, is_active) VALUES (?,?,?,?,1)')
            ->execute([self::CUSTOMER_ID, self::COMPANY_ID, 'customer', 'Cliente Ejemplo']);
        $this->pdo->prepare('INSERT INTO contacts (id, company_id, type, name, is_active) VALUES (?,?,?,?,1)')
            ->execute([self::VENDOR_ID, self::COMPANY_ID, 'vendor', 'Proveedor Ejemplo']);

        // Seed chart of accounts
        $accounts = [
            [self::CASH_ACCOUNT_ID, '1105', 'Caja', 'asset'],
            [self::RECEIVABLE_ACCOUNT_ID, '1305', 'Cuentas por Cobrar', 'asset'],
            [self::PAYABLE_ACCOUNT_ID, '2205', 'Cuentas por Pagar', 'liability'],
            [self::CAPITAL_ACCOUNT_ID, '3105', 'Capital Social', 'equity'],
            [self::REVENUE_ACCOUNT_ID, '4135', 'Ventas', 'income'],
            [self::EXPENSE_ACCOUNT_ID, '5105', 'Gastos Diversos', 'expense'],
        ];
        foreach ($accounts as $acc) {
            $this->pdo->prepare(
                'INSERT INTO chart_accounts (id, company_id, parent_id, code, name, account_type, is_header, is_active)
                 VALUES (?,?,NULL,?,?,?,0,1)'
            )->execute([$acc[0], self::COMPANY_ID, $acc[1], $acc[2], $acc[3]]);
        }

        // Seeding accounting postings
        // 1. Socio aporta capital: Caja 1000 / Capital 1000 el 2026-06-01
        $je1 = 'je111111-1111-1111-1111-111111111111';
        $this->pdo->prepare(
            'INSERT INTO journal_entries (id, company_id, branch_id, entry_number, entry_date, description, status, operating_currency, functional_currency, exchange_rate)
             VALUES (?,?,?, "JE-001", "2026-06-01", "Aporte capital", "posted", "USD", "USD", 1.0)'
        )->execute([$je1, self::COMPANY_ID, self::BRANCH_ID]);
        $this->pdo->prepare(
            'INSERT INTO journal_lines (id, journal_entry_id, chart_account_id, line_order, debit, credit, debit_functional, credit_functional)
             VALUES (?,?,?, 1, 1000.0, 0.0, 1000.0, 0.0)'
        )->execute(['jl1', $je1, self::CASH_ACCOUNT_ID]);
        $this->pdo->prepare(
            'INSERT INTO journal_lines (id, journal_entry_id, chart_account_id, line_order, debit, credit, debit_functional, credit_functional)
             VALUES (?,?,?, 2, 0.0, 1000.0, 0.0, 1000.0)'
        )->execute(['jl2', $je1, self::CAPITAL_ACCOUNT_ID]);

        // 2. Venta a crédito: CxC 500 / Ingresos 500 el 2026-06-15
        $je2 = 'je222222-2222-2222-2222-222222222222';
        $this->pdo->prepare(
            'INSERT INTO journal_entries (id, company_id, branch_id, entry_number, entry_date, description, status, operating_currency, functional_currency, exchange_rate)
             VALUES (?,?,?, "JE-002", "2026-06-15", "Venta credito", "posted", "USD", "USD", 1.0)'
        )->execute([$je2, self::COMPANY_ID, self::BRANCH_ID]);
        $this->pdo->prepare(
            'INSERT INTO journal_lines (id, journal_entry_id, chart_account_id, line_order, debit, credit, debit_functional, credit_functional)
             VALUES (?,?,?, 1, 500.0, 0.0, 500.0, 0.0)'
        )->execute(['jl3', $je2, self::RECEIVABLE_ACCOUNT_ID]);
        $this->pdo->prepare(
            'INSERT INTO journal_lines (id, journal_entry_id, chart_account_id, line_order, debit, credit, debit_functional, credit_functional)
             VALUES (?,?,?, 2, 0.0, 500.0, 0.0, 500.0)'
        )->execute(['jl4', $je2, self::REVENUE_ACCOUNT_ID]);

        // 3. Pago gasto: Gastos 200 / Caja 200 el 2026-06-20
        $je3 = 'je333333-3333-3333-3333-333333333333';
        $this->pdo->prepare(
            'INSERT INTO journal_entries (id, company_id, branch_id, entry_number, entry_date, description, status, operating_currency, functional_currency, exchange_rate)
             VALUES (?,?,?, "JE-003", "2026-06-20", "Gasto servicios", "posted", "USD", "USD", 1.0)'
        )->execute([$je3, self::COMPANY_ID, self::BRANCH_ID]);
        $this->pdo->prepare(
            'INSERT INTO journal_lines (id, journal_entry_id, chart_account_id, line_order, debit, credit, debit_functional, credit_functional)
             VALUES (?,?,?, 1, 200.0, 0.0, 200.0, 0.0)'
        )->execute(['jl5', $je3, self::EXPENSE_ACCOUNT_ID]);
        $this->pdo->prepare(
            'INSERT INTO journal_lines (id, journal_entry_id, chart_account_id, line_order, debit, credit, debit_functional, credit_functional)
             VALUES (?,?,?, 2, 0.0, 200.0, 0.0, 200.0)'
        )->execute(['jl6', $je3, self::CASH_ACCOUNT_ID]);

        // Seed sales invoice (unpaid, due 2026-07-15)
        $this->pdo->prepare(
            'INSERT INTO sales_invoices (id, company_id, branch_id, customer_id, receivable_account_id, invoice_number, invoice_date, due_date, reference, subtotal, discount_amount, tax_amount, currency_code, exchange_rate, total, balance, status)
             VALUES (?,?,?,?, ?, "INV-001", "2026-06-15", "2026-07-15", "Ref 1", 500.0, 0.0, 0.0, "USD", 1.0, 500.0, 500.0, "posted")'
        )->execute(['si1', self::COMPANY_ID, self::BRANCH_ID, self::CUSTOMER_ID, self::RECEIVABLE_ACCOUNT_ID]);

        // Seed purchase bill (unpaid, past due on 2026-06-22, due 2026-06-20)
        $this->pdo->prepare(
            'INSERT INTO purchases_bills (id, company_id, branch_id, vendor_id, payable_account_id, bill_number, bill_date, due_date, reference, subtotal, discount_amount, tax_amount, currency_code, exchange_rate, total, balance, status)
             VALUES (?,?,?,?, ?, "BILL-001", "2026-06-10", "2026-06-20", "Ref 2", 300.0, 0.0, 0.0, "USD", 1.0, 300.0, 300.0, "posted")'
        )->execute(['pb1', self::COMPANY_ID, self::BRANCH_ID, self::VENDOR_ID, self::PAYABLE_ACCOUNT_ID]);
    }

    private function configureEnv(): void
    {
        $_ENV['JWT_SECRET'] = 'test-jwt-secret';
        $_ENV['JWT_EXPIRES_IN'] = '15m';
        $_ENV['JWT_REFRESH_EXPIRES_DAYS'] = '7';
        $_ENV['JWT_KID'] = '';
        $_ENV['JWT_SECRET_PREVIOUS'] = '';
    }
}
