<?php

declare(strict_types=1);

namespace ApiModel\Tests\Integration\Http;

use ApiModel\Action\PurchasesAction;
use ApiModel\Infrastructure\Persistence\Repositories\PdoBillRepository;
use ApiModel\Infrastructure\Persistence\Repositories\PdoPurchasePaymentRepository;
use ApiModel\Infrastructure\Persistence\Repositories\PdoExpenseRepository;
use ApiModel\Infrastructure\Persistence\Repositories\PdoJournalRepository;
use ApiModel\Infrastructure\Persistence\Repositories\PdoChartAccountRepository;
use ApiModel\Infrastructure\Persistence\Repositories\PdoTaxRateRepository;
use ApiModel\Infrastructure\Persistence\Repositories\PdoCompanyRepository;
use ApiModel\Infrastructure\Persistence\Repositories\PdoBranchRepository;
use ApiModel\Infrastructure\Persistence\Repositories\PdoExchangeRateRepository;
use ApiModel\Infrastructure\Persistence\Repositories\PdoUserAccessRepository;
use ApiModel\Infrastructure\Persistence\Repositories\PdoProfileRepository;
use ApiModel\Middleware\CompanyContextMiddleware;
use ApiModel\Middleware\ApiErrorHandler;
use ApiModel\Route\PurchasesRoutes;
use ApiModel\Service\BillService;
use ApiModel\Service\PurchasePaymentService;
use ApiModel\Service\ExpenseService;
use ApiModel\Service\JournalService;
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 PurchasePaymentsRoutesTest 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 VENDOR_ID = 'v1111111-1111-1111-1111-111111111111';

    private const PAYABLE_ACCOUNT_ID = '22050500-0000-0000-0000-000000000001';
    private const CASH_ACCOUNT_ID = '11050500-0000-0000-0000-000000000002';
    private const EXPENSE_ACCOUNT_ID = '51050500-0000-0000-0000-000000000003';
    private string $billId;
    private string $billNumber;

    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');

        // Create outstanding posted bill
        $this->billId = 'b1111111-1111-1111-1111-111111111111';
        $this->billNumber = 'FB-000001';
        $this->seedBill();
    }

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

    public function testListPaymentsInitiallyEmpty(): void
    {
        $response = $this->request('GET', '/purchases/payments', $this->companyHeaders());

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

    public function testCreatePaymentReconcilesBillAndPostsJournal(): void
    {
        $payload = [
            'vendor_id' => self::VENDOR_ID,
            'chart_account_id' => self::CASH_ACCOUNT_ID,
            'payment_date' => '2026-06-22',
            'payment_method' => 'bank',
            'amount' => 180.0,
            'notes' => 'Pago a cuenta de factura',
            'lines' => [
                [
                    'bill_id' => $this->billId,
                    'amount' => 180.0,
                ]
            ]
        ];

        $response = $this->jsonRequest('POST', '/purchases/payments', $payload, $this->companyHeaders());
        $this->assertSame(200, $response->getStatusCode());

        $payment = $this->decodeBody($response);
        $this->assertArrayHasKey('id', $payment);
        $this->assertEquals(180.0, $payment['amount']);
        $this->assertSame('bank', $payment['payment_method']);

        // Assert bill balance is reduced and status is partially_paid (since total was 400)
        $stmt = $this->pdo->prepare('SELECT status, balance FROM purchases_bills WHERE id = ?');
        $stmt->execute([$this->billId]);
        $bill = $stmt->fetch();
        $this->assertSame('partially_paid', $bill['status']);
        $this->assertEquals(220.0, $bill['balance']);

        // Assert accounting journal was generated
        $stmtJe = $this->pdo->prepare('SELECT id FROM journal_entries WHERE entry_number = ? LIMIT 1');
        $stmtJe->execute([$payment['payment_number']]);
        $je = $stmtJe->fetch();
        $this->assertNotFalse($je);

        // Assert journal lines: Debit Payable 180, Credit Cash 180
        $stmtLines = $this->pdo->prepare('SELECT chart_account_id, debit, credit FROM journal_lines WHERE journal_entry_id = ? ORDER BY line_order ASC');
        $stmtLines->execute([$je['id']]);
        $lines = $stmtLines->fetchAll();

        $this->assertCount(2, $lines);
        $this->assertSame(self::CASH_ACCOUNT_ID, $lines[0]['chart_account_id']);
        $this->assertEquals(0.0, $lines[0]['debit']);
        $this->assertEquals(180.0, $lines[0]['credit']);

        $this->assertSame(self::PAYABLE_ACCOUNT_ID, $lines[1]['chart_account_id']);
        $this->assertEquals(180.0, $lines[1]['debit']);
        $this->assertEquals(0.0, $lines[1]['credit']);
    }

    public function testCreatePaymentWithWithholding(): void
    {
        $withholdingAccountId = '22051000-0000-0000-0000-000000000004';
        $payload = [
            'vendor_id' => self::VENDOR_ID,
            'chart_account_id' => self::CASH_ACCOUNT_ID,
            'payment_date' => '2026-06-22',
            'payment_method' => 'bank',
            'amount' => 380.0,
            'withholding_amount' => 20.0,
            'withholding_account_id' => $withholdingAccountId,
            'notes' => 'Pago a cuenta con retención',
            'lines' => [
                [
                    'bill_id' => $this->billId,
                    'amount' => 400.0,
                ]
            ]
        ];

        $response = $this->jsonRequest('POST', '/purchases/payments', $payload, $this->companyHeaders());
        $this->assertSame(200, $response->getStatusCode());

        $payment = $this->decodeBody($response);
        $this->assertArrayHasKey('id', $payment);
        $this->assertEquals(380.0, $payment['amount']);
        $this->assertEquals(20.0, $payment['withholding_amount']);
        $this->assertSame($withholdingAccountId, $payment['withholding_account_id']);

        // Assert Bill is fully paid
        $stmt = $this->pdo->prepare('SELECT status, balance FROM purchases_bills WHERE id = ?');
        $stmt->execute([$this->billId]);
        $bill = $stmt->fetch();
        $this->assertSame('paid', $bill['status']);
        $this->assertEquals(0.0, $bill['balance']);

        // Assert accounting journal was generated
        $stmtJe = $this->pdo->prepare('SELECT id FROM journal_entries WHERE entry_number = ? LIMIT 1');
        $stmtJe->execute([$payment['payment_number']]);
        $je = $stmtJe->fetch();
        $this->assertNotFalse($je);

        // Assert journal lines: Credit Cash 380, Credit Withholding 20, Debit Payable 400
        $stmtLines = $this->pdo->prepare('SELECT chart_account_id, debit, credit FROM journal_lines WHERE journal_entry_id = ? ORDER BY line_order ASC');
        $stmtLines->execute([$je['id']]);
        $lines = $stmtLines->fetchAll();

        $this->assertCount(3, $lines);

        // Line 0: Cash Credit (380)
        $this->assertSame(self::CASH_ACCOUNT_ID, $lines[0]['chart_account_id']);
        $this->assertEquals(0.0, $lines[0]['debit']);
        $this->assertEquals(380.0, $lines[0]['credit']);

        // Line 1: Withholding Credit (20)
        $this->assertSame($withholdingAccountId, $lines[1]['chart_account_id']);
        $this->assertEquals(0.0, $lines[1]['debit']);
        $this->assertEquals(20.0, $lines[1]['credit']);

        // Line 2: Payable Debit (400)
        $this->assertSame(self::PAYABLE_ACCOUNT_ID, $lines[2]['chart_account_id']);
        $this->assertEquals(400.0, $lines[2]['debit']);
        $this->assertEquals(0.0, $lines[2]['credit']);
    }

    public function testDeletePaymentRevertsBillBalancesAndRemovesJournal(): void
    {
        // 1. Post a payment of 400 (full payment)
        $payload = [
            'vendor_id' => self::VENDOR_ID,
            'chart_account_id' => self::CASH_ACCOUNT_ID,
            'payment_date' => '2026-06-22',
            'payment_method' => 'cash',
            'amount' => 400.0,
            'notes' => 'Cancelación total',
            'lines' => [
                [
                    'bill_id' => $this->billId,
                    'amount' => 400.0,
                ]
            ]
        ];
        $res = $this->jsonRequest('POST', '/purchases/payments', $payload, $this->companyHeaders());
        $payment = $this->decodeBody($res);
        $paymentId = $payment['id'];
        $paymentNumber = $payment['payment_number'];

        // Assert Bill status is paid and balance is 0
        $stmt = $this->pdo->prepare('SELECT status, balance FROM purchases_bills WHERE id = ?');
        $stmt->execute([$this->billId]);
        $bill = $stmt->fetch();
        $this->assertSame('paid', $bill['status']);
        $this->assertEquals(0.0, $bill['balance']);

        // 2. Delete payment
        $delRes = $this->request('DELETE', '/purchases/payments/' . $paymentId, $this->companyHeaders());
        $this->assertSame(200, $delRes->getStatusCode());

        // Assert Bill is reverted back to status='posted' and balance=400
        $stmtReverted = $this->pdo->prepare('SELECT status, balance FROM purchases_bills WHERE id = ?');
        $stmtReverted->execute([$this->billId]);
        $billReverted = $stmtReverted->fetch();
        $this->assertSame('posted', $billReverted['status']);
        $this->assertEquals(400.0, $billReverted['balance']);

        // Assert journal entry is deleted
        $stmtCountGone = $this->pdo->prepare('SELECT COUNT(*) FROM journal_entries WHERE entry_number = ?');
        $stmtCountGone->execute([$paymentNumber]);
        $this->assertEquals(0, $stmtCountGone->fetchColumn());
    }

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

        $orgRepo = new PdoCompanyRepository($this->pdo);
        $branchRepo = new PdoBranchRepository($this->pdo);
        $uaRepo = new PdoUserAccessRepository($this->pdo);
        $profRepo = new PdoProfileRepository($this->pdo);
        $orgService = new OrganizationService($orgRepo, $branchRepo, $uaRepo, $profRepo);
        
        $companyMiddleware = new CompanyContextMiddleware($orgService);

        $billRepo = new PdoBillRepository($this->pdo);
        $purchasePaymentRepo = new PdoPurchasePaymentRepository($this->pdo);
        $expenseRepo = new PdoExpenseRepository($this->pdo);
        $journalRepo = new PdoJournalRepository($this->pdo);
        $taxRateRepo = new PdoTaxRateRepository($this->pdo);
        $chartAccountRepo = new PdoChartAccountRepository($this->pdo);
        $exchangeRateRepo = new PdoExchangeRateRepository($this->pdo);

        $journalService = new JournalService($journalRepo, $chartAccountRepo, $orgRepo, $branchRepo, $exchangeRateRepo);
        
        $billService = new BillService($billRepo, $journalRepo, $taxRateRepo, $journalService, $this->pdo);
        $purchasePaymentService = new PurchasePaymentService($purchasePaymentRepo, $billRepo, $journalRepo, $journalService, $this->pdo);
        $expenseService = new ExpenseService($expenseRepo, $journalRepo, $taxRateRepo, $journalService, $this->pdo);

        $action = new PurchasesAction($billService, $purchasePaymentService, $expenseService);

        $uuid = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}';
        $app->group('', function ($g) use ($action, $uuid): void {
            PurchasesRoutes::register($g, $action, $uuid);
        });

        $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);
    }

    private function jsonRequest(string $method, string $path, array $payload, array $headers = []): ResponseInterface
    {
        $streamFactory = new StreamFactory();
        $requestFactory = new ServerRequestFactory();
        $body = $streamFactory->createStream((string) json_encode($payload, JSON_THROW_ON_ERROR));

        $request = $requestFactory
            ->createServerRequest($method, $path)
            ->withHeader('Content-Type', 'application/json')
            ->withBody($body);

        foreach ($headers as $name => $value) {
            $request = $request->withHeader($name, $value);
        }

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

    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.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.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.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 REFERENCES companies(id),
                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,
                UNIQUE (company_id, tax_id)
            )'
        );

        $this->pdo->exec(
            'CREATE TABLE chart_accounts (
                id TEXT PRIMARY KEY,
                parent_id TEXT NULL,
                company_id TEXT NOT 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,
                entry_number TEXT NOT NULL,
                entry_date TEXT NOT NULL,
                description TEXT,
                status TEXT NOT NULL DEFAULT "draft",
                operating_currency TEXT NOT NULL,
                functional_currency TEXT NOT NULL,
                exchange_rate REAL NOT NULL,
                created_by TEXT,
                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 REFERENCES journal_entries(id) ON DELETE CASCADE,
                chart_account_id TEXT NOT NULL REFERENCES chart_accounts(id),
                description TEXT,
                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,
                line_order INTEGER NOT NULL DEFAULT 0
            )'
        );

        $this->pdo->exec(
            'CREATE TABLE purchases_bills (
                id TEXT PRIMARY KEY,
                company_id TEXT NOT NULL,
                branch_id TEXT,
                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,
                currency_code TEXT NOT NULL DEFAULT "USD",
                exchange_rate REAL NOT NULL DEFAULT 1.0,
                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,
                balance REAL NOT NULL DEFAULT 0.0,
                status TEXT NOT NULL DEFAULT "draft",
                notes TEXT,
                created_by TEXT,
                created_at TEXT DEFAULT CURRENT_TIMESTAMP,
                updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
                UNIQUE (company_id, vendor_id, bill_number)
            )'
        );

        $this->pdo->exec(
            'CREATE TABLE purchases_bill_lines (
                id TEXT PRIMARY KEY,
                bill_id TEXT NOT NULL REFERENCES purchases_bills(id) ON DELETE CASCADE,
                description TEXT,
                quantity REAL NOT NULL DEFAULT 1.0,
                price REAL NOT NULL DEFAULT 0.0,
                tax_rate_id TEXT,
                tax_amount REAL NOT NULL DEFAULT 0.0,
                total REAL NOT NULL DEFAULT 0.0,
                chart_account_id TEXT NOT NULL,
                line_order INTEGER NOT NULL DEFAULT 0
            )'
        );

        $this->pdo->exec(
            'CREATE TABLE purchases_payments (
                id TEXT PRIMARY KEY,
                company_id TEXT NOT NULL,
                branch_id TEXT,
                vendor_id TEXT NOT NULL,
                payment_number TEXT NOT NULL,
                payment_date TEXT NOT NULL,
                payment_method TEXT NOT NULL DEFAULT "cash",
                amount REAL NOT NULL DEFAULT 0.0,
                currency_code TEXT NOT NULL DEFAULT "USD",
                exchange_rate REAL NOT NULL DEFAULT 1.0,
                chart_account_id TEXT NOT NULL,
                notes TEXT,
                created_by TEXT,
                withholding_amount REAL NOT NULL DEFAULT 0.0,
                withholding_account_id TEXT,
                created_at TEXT DEFAULT CURRENT_TIMESTAMP,
                updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
                UNIQUE (company_id, payment_number)
            )'
        );

        $this->pdo->exec(
            'CREATE TABLE purchases_payment_lines (
                id TEXT PRIMARY KEY,
                payment_id TEXT NOT NULL REFERENCES purchases_payments(id) ON DELETE CASCADE,
                bill_id TEXT NOT NULL REFERENCES purchases_bills(id) ON DELETE CASCADE,
                amount REAL NOT NULL DEFAULT 0.0,
                UNIQUE (payment_id, bill_id)
            )'
        );
    }

    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(['cccccccc-cccc-cccc-cccc-cccccccccccc', self::ADMIN_USER_ID, self::COMPANY_ID, self::BRANCH_ID]);

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

        // Seed Accounts
        $this->pdo->prepare('INSERT INTO chart_accounts (id, company_id, code, name, account_type, is_header) VALUES (?,?,?,?,?,0)')
            ->execute([self::PAYABLE_ACCOUNT_ID, self::COMPANY_ID, '220505', 'Proveedores Nacionales', 'liability']);

        $this->pdo->prepare('INSERT INTO chart_accounts (id, company_id, code, name, account_type, is_header) VALUES (?,?,?,?,?,0)')
            ->execute([self::CASH_ACCOUNT_ID, self::COMPANY_ID, '110505', 'Caja General', 'asset']);

        $this->pdo->prepare('INSERT INTO chart_accounts (id, company_id, code, name, account_type, is_header) VALUES (?,?,?,?,?,0)')
            ->execute([self::EXPENSE_ACCOUNT_ID, self::COMPANY_ID, '510505', 'Gastos Diversos', 'expense']);

        $this->pdo->prepare('INSERT INTO chart_accounts (id, company_id, code, name, account_type, is_header) VALUES (?,?,?,?,?,0)')
            ->execute(['22051000-0000-0000-0000-000000000004', self::COMPANY_ID, '220510', 'Retención Fuente por Pagar', 'liability']);
    }

    private function seedBill(): void
    {
        $this->pdo->prepare(
            'INSERT INTO purchases_bills (
                id, company_id, branch_id, vendor_id, payable_account_id,
                bill_number, bill_date, due_date, currency_code, exchange_rate,
                discount_amount, tax_amount, subtotal, total, balance, status
             ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, "USD", 1.0, 0.0, 0.0, 400.0, 400.0, 400.0, "posted")'
        )->execute([
            $this->billId,
            self::COMPANY_ID,
            self::BRANCH_ID,
            self::VENDOR_ID,
            self::PAYABLE_ACCOUNT_ID,
            $this->billNumber,
            '2026-06-22',
            '2026-07-22'
        ]);

        $this->pdo->prepare(
            'INSERT INTO purchases_bill_lines (
                id, bill_id, description, quantity, price, tax_amount, total, chart_account_id, line_order
             ) VALUES (?, ?, "Linea A", 1.0, 400.0, 0.0, 400.0, ?, 0)'
        )->execute([
            'l1111111-1111-1111-1111-111111111111',
            $this->billId,
            self::EXPENSE_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'] = '';
    }
}
