<?php
// Testes automatizados: cálculos de totais em Orçamentos (descontos por item, desconto/acréscimo global, frete)
// e persistência/edição/conversão para pedidos.

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

use Gestoreasy\Core\Http\Request;
use Gestoreasy\Core\Kernel;
use Gestoreasy\Core\Auth\Jwt;
use Gestoreasy\Core\Tenant\ConnectionManager;

function assertTrue($cond, $msg = '') { if(!$cond){ throw new Exception('ASSERT TRUE FAIL: ' . $msg); } }
function assertEq($exp, $act, $msg = '') { if($exp != $act){ throw new Exception("ASSERT EQ FAIL: $msg | exp=".var_export($exp,true)." act=".var_export($act,true)); } }
function assertStatus($res, $status, $msg = '') { assertTrue(($res->status ?? null) === $status, $msg . " (status " . ($res->status ?? 'null') . ")"); }
function r2($n){ return round((float)$n, 2); }

$kernel = new Kernel();
$payload = [ 'sub' => 1, 'email' => 'admin@local', 'name' => 'Admin', 'tenant' => 'default', 'roles' => ['admin'] ];
$token = Jwt::sign($payload);
$H = ['x-tenant-id' => 'default', 'authorization' => 'Bearer ' . $token];

// Arrange: cliente e produto base
$clientBody = [ 'tipo' => 'PF', 'cpf' => '529.982.247-25', 'nome_fantasia' => 'Cliente Testes Orçamentos', 'razao_social' => 'Cliente Testes Orçamentos Ltda', 'ie' => 'ISENTO', 'estado' => 'SP' ];
$reqClient = new Request($H, [], $clientBody, [], 'POST', '/api/clientes');
$resClient = $kernel->handle($reqClient); assertStatus($resClient, 201, 'Criar cliente');
$clienteId = (int)($resClient->body['id'] ?? 0); assertTrue($clienteId > 0, 'ID cliente > 0');

$prodBody = [ 'codigo' => 'SKU-QUOTES-001', 'ncm' => '12345678', 'cfop' => '5102', 'preco' => 100.00 ];
$reqProd = new Request($H, [], $prodBody, [], 'POST', '/api/produtos');
$resProd = $kernel->handle($reqProd); assertStatus($resProd, 201, 'Criar produto');
$produtoId = (int)($resProd->body['id'] ?? 0); assertTrue($produtoId > 0, 'ID produto > 0');

// Cenário 1: Desconto por item apenas
$orc1 = [
  'cliente_id' => $clienteId,
  'items' => [ ['product_id' => $produtoId, 'quantidade' => 2, 'desconto_percent' => 10] ],
  'pagamento' => ['desconto_percent' => 0, 'acrescimo_percent' => 0],
  'entrega' => ['frete' => 0, 'frete_incluir_total' => false]
];
$resOrc1 = $kernel->handle(new Request($H, [], $orc1, [], 'POST', '/api/vendas/orcamentos'));
assertStatus($resOrc1, 201, 'Criar orçamento c/ desconto item'); $orc1Id = (int)($resOrc1->body['id'] ?? 0);
$resGet1 = $kernel->handle(new Request($H, [], [], [], 'GET', "/api/vendas/orcamentos/$orc1Id"));
assertStatus($resGet1, 200, 'Obter orçamento #1'); $tot1 = (float)($resGet1->body['data']['quote']['valor_total'] ?? -1);
assertTrue(abs($tot1 - r2(2*100*0.9)) < 0.0001, 'Total item-desc 10%');

// Cenário 2: Desconto global 5%
$orc2 = [ 'cliente_id' => $clienteId, 'items' => [ ['product_id' => $produtoId, 'quantidade' => 2 ] ], 'pagamento' => ['desconto_percent' => 5], 'entrega' => ['frete' => 0, 'frete_incluir_total' => false] ];
$resOrc2 = $kernel->handle(new Request($H, [], $orc2, [], 'POST', '/api/vendas/orcamentos'));
assertStatus($resOrc2, 201, 'Criar orçamento c/ desconto global'); $orc2Id = (int)($resOrc2->body['id'] ?? 0);
$resGet2 = $kernel->handle(new Request($H, [], [], [], 'GET', "/api/vendas/orcamentos/$orc2Id"));
assertStatus($resGet2, 200, 'Obter orçamento #2'); $tot2 = (float)($resGet2->body['data']['quote']['valor_total'] ?? -1);
assertTrue(abs($tot2 - r2(2*100*0.95)) < 0.0001, 'Total global-desc 5%');

// Cenário 3: Acréscimo global 10%
$orc3 = [ 'cliente_id' => $clienteId, 'items' => [ ['product_id' => $produtoId, 'quantidade' => 2 ] ], 'pagamento' => ['acrescimo_percent' => 10], 'entrega' => ['frete' => 0, 'frete_incluir_total' => false] ];
$resOrc3 = $kernel->handle(new Request($H, [], $orc3, [], 'POST', '/api/vendas/orcamentos'));
assertStatus($resOrc3, 201, 'Criar orçamento c/ acrescimo global'); $orc3Id = (int)($resOrc3->body['id'] ?? 0);
$resGet3 = $kernel->handle(new Request($H, [], [], [], 'GET', "/api/vendas/orcamentos/$orc3Id"));
assertStatus($resGet3, 200, 'Obter orçamento #3'); $tot3 = (float)($resGet3->body['data']['quote']['valor_total'] ?? -1);
assertTrue(abs($tot3 - r2(2*100*1.10)) < 0.0001, 'Total global-acresc 10%');

// Cenário 4: Frete incluído (R$ 50)
$orc4 = [ 'cliente_id' => $clienteId, 'items' => [ ['product_id' => $produtoId, 'quantidade' => 2 ] ], 'pagamento' => [], 'entrega' => ['frete' => 50, 'frete_incluir_total' => true] ];
$resOrc4 = $kernel->handle(new Request($H, [], $orc4, [], 'POST', '/api/vendas/orcamentos'));
assertStatus($resOrc4, 201, 'Criar orçamento c/ frete incluído'); $orc4Id = (int)($resOrc4->body['id'] ?? 0);
$resGet4 = $kernel->handle(new Request($H, [], [], [], 'GET', "/api/vendas/orcamentos/$orc4Id"));
assertStatus($resGet4, 200, 'Obter orçamento #4'); $tot4 = (float)($resGet4->body['data']['quote']['valor_total'] ?? -1);
assertTrue(abs($tot4 - r2(200 + 50)) < 0.0001, 'Total com frete somado');

// Cenário 5: Combinação (item 10% + global 5% + acresc 20% + frete 30)
$orc5 = [
  'cliente_id' => $clienteId,
  'items' => [ ['product_id' => $produtoId, 'quantidade' => 2, 'desconto_percent' => 10 ] ],
  'pagamento' => ['desconto_percent' => 5, 'acrescimo_percent' => 20],
  'entrega' => ['frete' => 30, 'frete_incluir_total' => true]
];
$resOrc5 = $kernel->handle(new Request($H, [], $orc5, [], 'POST', '/api/vendas/orcamentos'));
assertStatus($resOrc5, 201, 'Criar orçamento combinado'); $orc5Id = (int)($resOrc5->body['id'] ?? 0);
$resGet5 = $kernel->handle(new Request($H, [], [], [], 'GET', "/api/vendas/orcamentos/$orc5Id"));
assertStatus($resGet5, 200, 'Obter orçamento #5'); $tot5 = (float)($resGet5->body['data']['quote']['valor_total'] ?? -1);
$expected5 = r2(r2(r2(2*100*0.9) * 0.95) * 1.20 + 30);
assertTrue(abs($tot5 - $expected5) < 0.0001, 'Total combinado item/global/frete');

// Cenário 6: Atualizar orçamento e recalcular total
$updBody = [
  'items' => [ ['product_id' => $produtoId, 'quantidade' => 3 ] ],
  'pagamento' => ['desconto_percent' => 10],
  'entrega' => ['frete' => 20, 'frete_incluir_total' => true]
];
$resUpd = $kernel->handle(new Request($H, [], $updBody, [], 'PUT', "/api/vendas/orcamentos/$orc2Id"));
assertStatus($resUpd, 200, 'Atualizar orçamento #2');
$resGet2b = $kernel->handle(new Request($H, [], [], [], 'GET', "/api/vendas/orcamentos/$orc2Id"));
assertStatus($resGet2b, 200, 'Obter orçamento #2 após update');
$tot2b = (float)($resGet2b->body['data']['quote']['valor_total'] ?? -1);
$expected2b = r2(r2(3*100) * 0.90 + 20);
assertTrue(abs($tot2b - $expected2b) < 0.0001, 'Total após update com desconto e frete');

// Cenário 7: Frete não somado
$orc6 = [ 'cliente_id' => $clienteId, 'items' => [ ['product_id' => $produtoId, 'quantidade' => 1 ] ], 'entrega' => ['frete' => 999.99, 'frete_incluir_total' => false] ];
$resOrc6 = $kernel->handle(new Request($H, [], $orc6, [], 'POST', '/api/vendas/orcamentos'));
assertStatus($resOrc6, 201, 'Criar orçamento c/ frete não somado'); $orc6Id = (int)($resOrc6->body['id'] ?? 0);
$resGet6 = $kernel->handle(new Request($H, [], [], [], 'GET', "/api/vendas/orcamentos/$orc6Id"));
assertStatus($resGet6, 200, 'Obter orçamento #6'); $tot6 = (float)($resGet6->body['data']['quote']['valor_total'] ?? -1);
assertTrue(abs($tot6 - 100.00) < 0.0001, 'Total sem somar frete');

// Cenário 8: Converter orçamento combinado (#5) em pedido e validar total
$resAprov5 = $kernel->handle(new Request($H, [], ['status' => 'aprovado'], [], 'PUT', "/api/vendas/orcamentos/$orc5Id"));
assertStatus($resAprov5, 200, 'Aprovar orçamento #5');
$resConv5 = $kernel->handle(new Request($H, [], [], [], 'POST', "/api/vendas/orcamentos/$orc5Id/converter"));
assertStatus($resConv5, 201, 'Converter orçamento #5'); $order5Id = (int)($resConv5->body['order_id'] ?? 0);
assertTrue($order5Id > 0, 'ID do pedido convertido > 0');
$resGetOrder5 = $kernel->handle(new Request($H, [], [], [], 'GET', "/api/vendas/pedidos/$order5Id"));
assertStatus($resGetOrder5, 200, 'Obter pedido convertido #5'); $orderTot5 = (float)($resGetOrder5->body['data']['order']['valor_total'] ?? -1);
assertTrue(abs($orderTot5 - $expected5) < 0.0001, 'Pedido convertido mantém total do orçamento');

echo "PASS: SalesQuotesTotalsTest (cálculos de descontos/acréscimos/frete e persistência).\n";