<?php
require_once __DIR__ . '/../bootstrap.php';

use Gestoreasy\Core\Tenant\TenantAdmin;
use Gestoreasy\Core\Tenant\ConnectionManager;
use Gestoreasy\Core\Fiscal\Sped\SpedFiscalGenerator;
use Gestoreasy\Core\Fiscal\Sped\Period as SpedPeriod;
use Gestoreasy\Core\Fiscal\Sped\Validation\SpedValidator;

function assertTrue($c,$m){ if(!$c){ echo "FAIL: $m\n"; exit(1);} }
function assertContainsLinePrefix(array $lines, string $prefix, string $msg){
    foreach ($lines as $l) { if (str_starts_with($l, $prefix)) return; }
    echo "FAIL: $msg\n"; exit(1);
}

$tenant = $argv[1] ?? 'default';
TenantAdmin::runMigrations($tenant);
$pdo = ConnectionManager::forTenant($tenant);

// Seed minimal company, product, client and supplier
$pdo->exec("INSERT INTO empresas (nome, razao_social, cnpj, ie, email, telefone, estado, cep, logradouro, numero, bairro, cidade, created_at)
    SELECT 'Empresa Demo', 'Empresa Demo Ltda', '12.345.678/0001-99', '123456789', 'contato@demo.com', '(21)3333-3333', 'RJ', '20000000', 'Rua Demo', '100', 'Centro', 'Rio de Janeiro', NOW()
    WHERE NOT EXISTS (SELECT 1 FROM empresas)");
$pdo->exec("INSERT INTO products (codigo, descricao, ean, unidade, ncm) VALUES ('SKU1','Produto 1','1234567890123','UN','00000000')");
$pdo->exec("INSERT INTO clients (nome, cnpj) VALUES ('Cliente Teste','11.222.333/0001-44')");
$pdo->exec("INSERT INTO suppliers (nome, cnpj) VALUES ('Fornecedor Teste','55.666.777/0001-88')");

// Create a sales order with one item in the current period
$pdo->exec("INSERT INTO sales_orders (numero, cliente_id, valor_total, status, created_at) VALUES ('SO-001', (SELECT id FROM clients ORDER BY id DESC LIMIT 1), 100.00, 'aberto', NOW())");
$orderId = (int)$pdo->query("SELECT id FROM sales_orders WHERE numero='SO-001'")->fetch()['id'];
$productId = (int)$pdo->query("SELECT id FROM products WHERE codigo='SKU1'")->fetch()['id'];
$pdo->exec("INSERT INTO sales_order_items (order_id, product_id, quantidade, preco, total) VALUES ($orderId, $productId, 2.000, 50.00, 100.00)");

// Create a purchase invoice with one item in the current period
$supplierId = (int)$pdo->query("SELECT id FROM suppliers ORDER BY id DESC LIMIT 1")->fetch()['id'];
$pdo->exec("INSERT INTO purchase_invoices (numero, fornecedor_id, valor, data_emissao) VALUES ('PI-001', $supplierId, 200.00, DATE(NOW()))");
$invoiceId = (int)$pdo->query("SELECT id FROM purchase_invoices WHERE numero='PI-001'")->fetch()['id'];
$pdo->exec("INSERT INTO purchase_invoice_items (invoice_id, product_id, quantidade, preco, total) VALUES ($invoiceId, $productId, 4.000, 50.00, 200.00)");

$gen = new SpedFiscalGenerator($pdo);
$period = new SpedPeriod((int)date('Y'), (int)date('n'));
$lines = $gen->generate($period, ['perfil' => 'A', 'ind_ativ' => 1]);

// Block C presence
assertTrue(in_array('|C001|0|', $lines, true), 'Contains C001 open record');
assertContainsLinePrefix($lines, '|C100|', 'Contains at least one C100 record');
assertContainsLinePrefix($lines, '|C170|', 'Contains at least one C170 record');
// Check CFOP/CST hints in any C170 line
$foundCFOP = false; $foundCST = false;
foreach ($lines as $l){
    if (str_starts_with($l, '|C170|')) {
        if (str_contains($l, '|5102|') || str_contains($l, '|1102|')) $foundCFOP = true;
        if (str_contains($l, '|000|')) $foundCST = true;
    }
}
assertTrue($foundCFOP, 'C170 contains CFOP default (5102/1102)');
assertTrue($foundCST, 'C170 contains CST default (000)');
// Check ICMS/PIS/COFINS bases and aliquots present in C170
$foundTaxFields = false;
foreach ($lines as $l){
    if (str_starts_with($l, '|C170|')) {
        $p = explode('|', $l);
        // indexes per our formatter: 12=VL_BC_ICMS, 13=ALIQ_ICMS, 14=VL_ICMS, 24=VL_BC_PIS, 25=ALIQ_PIS, 26=VL_PIS, 28=VL_BC_COFINS, 29=ALIQ_COFINS, 30=VL_COFINS
        if (isset($p[12],$p[13],$p[14],$p[24],$p[25],$p[26],$p[28],$p[29],$p[30]) && $p[13] !== '' && $p[25] !== '' && $p[29] !== '') {
            $foundTaxFields = true; break;
        }
    }
}
assertTrue($foundTaxFields, 'C170 includes ICMS/PIS/COFINS bases and aliquots');
// Consolidation record
assertContainsLinePrefix($lines, '|C190|', 'Contains at least one C190 consolidation record');
// Check C190 contains non-zero base and ICMS value
$foundC190Values = false;
foreach ($lines as $l){
    if (str_starts_with($l, '|C190|')) {
        $p = explode('|', $l);
        // indexes: 4=ALIQ_ICMS, 6=VL_BC_ICMS, 7=VL_ICMS
        if (isset($p[4],$p[6],$p[7]) && $p[4] !== '' && $p[6] !== '0.00' && $p[7] !== '0.00') { $foundC190Values = true; break; }
    }
}
assertTrue($foundC190Values, 'C190 includes ALIQ_ICMS and non-zero VL_BC_ICMS/VL_ICMS');
assertContainsLinePrefix($lines, '|C990|', 'Contains C990 close record');

// Cross-check: sum VL_BC_ICMS and VL_ICMS across C170 equals sum across C190
$sumC170Bc = 0.0; $sumC170Icms = 0.0;
foreach ($lines as $l){
    if (str_starts_with($l, '|C170|')) {
        $p = explode('|', $l);
        $sumC170Bc += (float)($p[12] ?? 0);
        $sumC170Icms += (float)($p[14] ?? 0);
    }
}
$sumC190Bc = 0.0; $sumC190Icms = 0.0;
foreach ($lines as $l){
    if (str_starts_with($l, '|C190|')) {
        $p = explode('|', $l);
        $sumC190Bc += (float)($p[6] ?? 0);
        $sumC190Icms += (float)($p[7] ?? 0);
    }
}
assertTrue(number_format($sumC170Bc,2,'.','') === number_format($sumC190Bc,2,'.',''), 'C190 VL_BC_ICMS equals sum of C170 bases');
assertTrue(number_format($sumC170Icms,2,'.','') === number_format($sumC190Icms,2,'.',''), 'C190 VL_ICMS equals sum of C170 ICMS');

// Block E presence
assertTrue(in_array('|E001|0|', $lines, true), 'Contains E001 open record');
assertContainsLinePrefix($lines, '|E100|', 'Contains E100 period record');
assertContainsLinePrefix($lines, '|E110|', 'Contains E110 apuração record');
// Validate basic ICMS apuração values using default rate 0.18
$e110 = null;
foreach ($lines as $l) { if (str_starts_with($l, '|E110|')) { $e110 = $l; break; } }
assertTrue($e110 !== null, 'Found E110 line');
$parts = explode('|', $e110);
// indexes: 2=VL_TOT_DEBITOS, 4=VL_TOT_CREDITOS, 9=VL_SLD_APURADO, 11=VL_ICMS_RECOLHER, 12=VL_SLD_CREDOR_TRANSPORTAR
// Compute expected values from DB to avoid interference from existing data
$start = $period->startDate(); $end = $period->endDate(); $rate = 0.18;
$salesTotal = (float)($pdo->query("SELECT COALESCE(SUM(valor_total),0) AS t FROM sales_orders WHERE DATE(created_at) BETWEEN '$start' AND '$end'")->fetch()['t'] ?? 0);
$purchaseTotal = (float)($pdo->query("SELECT COALESCE(SUM(valor),0) AS t FROM purchase_invoices WHERE DATE(data_emissao) BETWEEN '$start' AND '$end'")->fetch()['t'] ?? 0);
$expDeb = number_format($salesTotal * $rate, 2, '.', '');
$expCred = number_format($purchaseTotal * $rate, 2, '.', '');
$sldAp = number_format(0 + ($salesTotal*$rate) - ($purchaseTotal*$rate) - 0 + 0 - 0, 2, '.', '');
$expRec = ((float)$sldAp >= 0) ? $sldAp : '0.00';
$expCredTransp = ((float)$sldAp < 0) ? number_format(abs((float)$sldAp), 2, '.', '') : '0.00';
assertTrue(isset($parts[2]) && $parts[2] === $expDeb, 'E110 VL_TOT_DEBITOS matches');
assertTrue(isset($parts[4]) && $parts[4] === $expCred, 'E110 VL_TOT_CREDITOS matches');
assertTrue(isset($parts[9]) && $parts[9] === $sldAp, 'E110 VL_SLD_APURADO matches');
assertTrue(isset($parts[11]) && $parts[11] === $expRec, 'E110 VL_ICMS_RECOLHER matches');
assertTrue(isset($parts[12]) && $parts[12] === $expCredTransp, 'E110 VL_SLD_CREDOR_TRANSPORTAR matches');
assertContainsLinePrefix($lines, '|E990|', 'Contains E990 close record');

// Block 1 presence
assertTrue(in_array('|1001|1|', $lines, true), 'Contains 1001 open record');
assertContainsLinePrefix($lines, '|1990|', 'Contains 1990 close record');

// Blocks H and K presence
assertTrue(in_array('|H001|0|', $lines, true), 'Contains H001 open record');
assertContainsLinePrefix($lines, '|H990|', 'Contains H990 close record');
assertTrue(in_array('|K001|0|', $lines, true), 'Contains K001 open record');
assertContainsLinePrefix($lines, '|K990|', 'Contains K990 close record');

// Final trailer still present
$last = $lines[count($lines)-1] ?? '';
assertTrue(str_starts_with($last, '|9999|'), 'Last record is 9999');

echo "OK: SpedFiscalGenerator blocks C/E/H/K/1 present and serialized correctly\n";

// Run validator to ensure no issues found
$issues = SpedValidator::validateSpedLines($lines);
assertTrue(empty($issues), 'SpedValidator reported issues: '.implode('; ', $issues));
echo "OK: SpedValidator found no issues in generated lines\n";