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

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

function assertEq($a, $b, $msg) { if ($a !== $b) { echo "FAIL: $msg (" . var_export($a, true) . " !== " . var_export($b, true) . ")\n"; exit(1); } }
function assertTrue($cond, $msg) { if (!$cond) { echo "FAIL: $msg\n"; exit(1); } }

echo "Financeiro: aprovações multi-nível, filtros e bloqueio de pagamento\n\n";

$kernel = new Kernel();

// Token com bypass de RBAC via impersonated
$payload = [
  'sub' => 1,
  'email' => 'admin@local',
  'name' => 'Admin',
  'tenant' => 'default',
  'roles' => ['admin'],
  'impersonated' => true
];
$token = Jwt::sign($payload);
$authHeaders = [
  'x-tenant-id' => 'default',
  'authorization' => 'Bearer ' . $token
];

// Preparar tabelas (ambientes sem migrações completas)
$pdo = ConnectionManager::forTenant('default');
$pdo->exec('CREATE TABLE IF NOT EXISTS contas_pagar (
  id INT AUTO_INCREMENT PRIMARY KEY,
  descricao VARCHAR(255) NOT NULL,
  fornecedor VARCHAR(255) NOT NULL,
  valor DECIMAL(12,2) NOT NULL,
  documento VARCHAR(100) NULL,
  observacoes TEXT NULL,
  status VARCHAR(20) NOT NULL DEFAULT "pendente",
  data_vencimento DATE NOT NULL,
  data_pagamento DATE NULL,
  valor_pago DECIMAL(12,2) NULL,
  forma_pagamento VARCHAR(50) NULL,
  observacoes_pagamento TEXT NULL,
  reconciled_at DATETIME NULL,
  reconciliation_reference VARCHAR(100) NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NULL
)');
$pdo->exec('CREATE TABLE IF NOT EXISTS contas_pagar_pagamentos (
  id INT AUTO_INCREMENT PRIMARY KEY,
  conta_id INT NOT NULL,
  data_pagamento DATE NOT NULL,
  valor_pago DECIMAL(12,2) NOT NULL,
  forma_pagamento VARCHAR(50) NOT NULL,
  observacoes TEXT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  INDEX idx_pag_conta (conta_id)
)');
$pdo->exec('CREATE TABLE IF NOT EXISTS contas_pagar_aprovacoes (
  id INT AUTO_INCREMENT PRIMARY KEY,
  conta_id INT NOT NULL,
  level INT NOT NULL,
  status VARCHAR(20) NOT NULL,
  approved_by INT NULL,
  approved_at TIMESTAMP NULL,
  notes TEXT NULL,
  INDEX idx_apr_conta (conta_id)
)');

$tag = 'APPR_' . time();
$today = date('Y-m-d');

// Criar contas: A(4000), B(6000), C(6000), D(4000)
$create = function($desc, $valor, $doc){
  global $kernel, $authHeaders, $today, $tag;
  $body = [
    'descricao' => $desc . ' ' . $tag,
    'valor' => $valor,
    'data_vencimento' => date('Y-m-d', strtotime($today . ' +3 days')),
    'fornecedor' => 'Tech Ltda',
    'documento' => $doc
  ];
  $req = new Request($authHeaders, [], $body, [], 'POST', '/api/financeiro/contas-pagar');
  $res = $kernel->handle($req);
  assertEq($res->status, 201, 'Criar conta ' . $desc);
  return (int)($res->body['id'] ?? 0);
};

$idA = $create('Conta A', 4000.00, 'DOC-A');
$idB = $create('Conta B', 6000.00, 'DOC-B');
$idC = $create('Conta C', 6000.00, 'DOC-C');
$idD = $create('Conta D', 4000.00, 'DOC-D');

// Aprovações nível 1: A(aprovado), B(aprovado), C(rejeitado)
$approve = function($id, $level, $status, $notes){
  global $kernel, $authHeaders;
  $req = new Request($authHeaders, [], ['level' => $level, 'status' => $status, 'notes' => $notes], [], 'POST', "/api/financeiro/contas-pagar/$id/aprovar");
  $res = $kernel->handle($req);
  assertEq($res->status, 200, "Aprovação conta $id nível $level -> $status");
};

$approve($idA, 1, 'aprovado', 'ok a1');
$approve($idB, 1, 'aprovado', 'ok b1');
$approve($idC, 1, 'rejeitado', 'rej c1');

// Helpers de listagem com filtros de aprovação
$list = function($level, $status){
  global $kernel, $authHeaders, $tag;
  $query = [
    'q' => $tag,
    'approval_level' => $level,
    'approval_status' => $status
  ];
  $req = new Request($authHeaders, $query, [], [], 'GET', '/api/financeiro/contas-pagar');
  $res = $kernel->handle($req);
  assertEq($res->status, 200, "Listar approval_level=$level approval_status=$status");
  return $res->body['data'] ?? [];
};

// 1) Filtros nível 1 aprovado: deve conter A e B, não C/D
$rows = $list(1, 'aprovado');
$ids = array_map(fn($r) => (int)($r['id'] ?? 0), $rows);
assertTrue(in_array($idA, $ids), 'N1 aprovado inclui A');
assertTrue(in_array($idB, $ids), 'N1 aprovado inclui B');
assertTrue(!in_array($idC, $ids), 'N1 aprovado exclui C');
assertTrue(!in_array($idD, $ids), 'N1 aprovado exclui D');

// 2) Filtros nível 1 rejeitado: deve conter apenas C
$rows = $list(1, 'rejeitado');
$ids = array_map(fn($r) => (int)($r['id'] ?? 0), $rows);
assertTrue(in_array($idC, $ids), 'N1 rejeitado inclui C');
assertTrue(!in_array($idA, $ids), 'N1 rejeitado exclui A');
assertTrue(!in_array($idB, $ids), 'N1 rejeitado exclui B');
assertTrue(!in_array($idD, $ids), 'N1 rejeitado exclui D');

// 3) Filtros nível 1 pendente: deve conter D apenas
$rows = $list(1, 'pendente');
$ids = array_map(fn($r) => (int)($r['id'] ?? 0), $rows);
assertTrue(in_array($idD, $ids), 'N1 pendente inclui D');
assertTrue(!in_array($idA, $ids), 'N1 pendente exclui A');
assertTrue(!in_array($idB, $ids), 'N1 pendente exclui B');
assertTrue(!in_array($idC, $ids), 'N1 pendente exclui C');

// 4) Filtros nível 2 pendente: deve conter B e C (>= threshold)
$rows = $list(2, 'pendente');
$ids = array_map(fn($r) => (int)($r['id'] ?? 0), $rows);
assertTrue(in_array($idB, $ids), 'N2 pendente inclui B');
assertTrue(in_array($idC, $ids), 'N2 pendente inclui C');
assertTrue(!in_array($idA, $ids), 'N2 pendente exclui A');
assertTrue(!in_array($idD, $ids), 'N2 pendente exclui D');

// 5) Pagamento bloqueado enquanto faltam aprovações: B requer N2
$reqPayBlocked = new Request($authHeaders, [], ['forma_pagamento' => 'pix'], [], 'POST', "/api/financeiro/contas-pagar/$idB/pagar");
$resPayBlocked = $kernel->handle($reqPayBlocked);
assertEq($resPayBlocked->status, 403, 'Pagamento bloqueado para B com N2 pendente');
$bodyBlocked = $resPayBlocked->body;
assertEq((int)($bodyBlocked['required_levels'] ?? 0), 2, 'required_levels=2');
assertEq((int)($bodyBlocked['approved_levels'] ?? 0), 1, 'approved_levels=1');

// 6) Aprovar N2 e pagar B
$approve($idB, 2, 'aprovado', 'ok b2');
$reqPayOk = new Request($authHeaders, [], ['forma_pagamento' => 'pix'], [], 'POST', "/api/financeiro/contas-pagar/$idB/pagar");
$resPayOk = $kernel->handle($reqPayOk);
assertEq($resPayOk->status, 200, 'Pagamento autorizado para B após N2 aprovado');

// 7) Histórico de aprovações (C deve ter N1 rejeitado com notas)
$reqHistAppr = new Request($authHeaders, [], [], [], 'GET', "/api/financeiro/contas-pagar/$idC/aprovacoes");
$resHistAppr = $kernel->handle($reqHistAppr);
assertEq($resHistAppr->status, 200, 'Historico de aprovações 200');
$histAppr = $resHistAppr->body['data'] ?? [];
assertTrue(is_array($histAppr) && count($histAppr) >= 1, 'Histórico de aprovações deve ter ao menos 1 linha');
$row = $histAppr[0];
assertEq((int)($row['level'] ?? 0), 1, 'Hist nível 1');
assertEq((string)($row['status'] ?? ''), 'rejeitado', 'Hist status rejeitado');
assertEq((string)($row['notes'] ?? ''), 'rej c1', 'Hist notas preservadas');

echo "PASS: FinanceiroContasPagarApprovalsAndFiltersTest (aprovações, filtros, bloqueio pagamento, histórico com notas)\n";