<?php
declare(strict_types=1);

// ✅ garante JSON mesmo em fatal error
ini_set('display_errors', '0');
error_reporting(E_ALL);
register_shutdown_function(function () {
  $e = error_get_last();
  if ($e && in_array($e['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR], true)) {
    if (!headers_sent()) {
      header("Content-Type: application/json; charset=utf-8", true, 500);
    }
    echo json_encode(["ok"=>false, "error"=>"Erro fatal PHP: ".$e['message']], JSON_UNESCAPED_UNICODE);
  }
});

require_once __DIR__ . "/../../includes/db.php";
require_once __DIR__ . "/../../includes/session_staff.php";

header("Content-Type: application/json; charset=utf-8");

function jexit(array $j, int $code=200): void {
  http_response_code($code);
  echo json_encode($j, JSON_UNESCAPED_UNICODE);
  exit;
}

if (session_status() !== PHP_SESSION_ACTIVE) {
  session_start();
}

function json_input(): array {
  $raw = file_get_contents("php://input");
  $data = json_decode($raw, true);
  return is_array($data) ? $data : [];
}

/** ✅ usa seu sistema de sessão real */
function must_staff_user_id(): int {
  if (!function_exists('staff_is_logged') || !staff_is_logged()) {
    jexit(["ok"=>false, "error"=>"Faça login novamente."], 401);
  }
  $s = function_exists('staff_current') ? staff_current() : [];
  $id = (int)($s['id'] ?? 0);
  if ($id <= 0) jexit(["ok"=>false, "error"=>"Faça login novamente."], 401);
  return $id;
}

/** ========= Helpers de schema (auto-detecção) ========= */
function column_exists(PDO $pdo, string $table, string $column): bool {
  $st = $pdo->prepare("
    SELECT COUNT(*) c
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_SCHEMA = DATABASE()
      AND TABLE_NAME = ?
      AND COLUMN_NAME = ?
  ");
  $st->execute([$table, $column]);
  return ((int)$st->fetchColumn()) > 0;
}

function table_exists(PDO $pdo, string $table): bool {
  $st = $pdo->prepare("
    SELECT COUNT(*) c
    FROM INFORMATION_SCHEMA.TABLES
    WHERE TABLE_SCHEMA = DATABASE()
      AND TABLE_NAME = ?
  ");
  $st->execute([$table]);
  return ((int)$st->fetchColumn()) > 0;
}

function pick_first_existing_column(PDO $pdo, string $table, array $candidates): ?string {
  foreach ($candidates as $col) {
    if (column_exists($pdo, $table, $col)) return $col;
  }
  return null;
}

function pick_first_existing_table(PDO $pdo, array $candidates): ?string {
  foreach ($candidates as $t) {
    if (table_exists($pdo, $t)) return $t;
  }
  return null;
}

/**
 * Calcula total_fatura e total_pago da conta:
 * 1) Usa contas.total_fatura/total_pago se existirem
 * 2) Senão tenta somar itens de pedidos via tabela de itens (auto-detect)
 */
function calcular_totais_conta(PDO $pdo, int $contaId): array {
  // pega conta básica
  $st = $pdo->prepare("SELECT id, status FROM contas WHERE id=? LIMIT 1");
  $st->execute([$contaId]);
  $c = $st->fetch(PDO::FETCH_ASSOC);
  if (!$c) {
    throw new Exception("Conta não encontrada");
  }

  $totalPago = 0.0;
  $totalFatura = 0.0;

  // 1) total_pago e total_fatura na própria tabela contas (se existirem)
  $hasTotalPago   = column_exists($pdo, 'contas', 'total_pago');
  $hasTotalFatura = column_exists($pdo, 'contas', 'total_fatura');

  if ($hasTotalPago || $hasTotalFatura) {
    $cols = "id, status";
    if ($hasTotalFatura) $cols .= ", total_fatura";
    if ($hasTotalPago)   $cols .= ", total_pago";

    $st2 = $pdo->prepare("SELECT $cols FROM contas WHERE id=? LIMIT 1");
    $st2->execute([$contaId]);
    $cc = $st2->fetch(PDO::FETCH_ASSOC) ?: [];

    $totalFatura = $hasTotalFatura ? (float)($cc['total_fatura'] ?? 0) : 0.0;
    $totalPago   = $hasTotalPago   ? (float)($cc['total_pago']   ?? 0) : 0.0;

    // Se já tem total_fatura > 0, usamos sem inventar
    if ($totalFatura > 0.0001) {
      return [
        'conta' => ['id'=>(int)$c['id'], 'status'=>(string)$c['status']],
        'total_fatura' => $totalFatura,
        'total_pago' => $totalPago,
      ];
    }
  }

  // 2) Somar por itens dos pedidos (pedidos não tem valor)
  // tenta descobrir a tabela de itens
  $itensTable = pick_first_existing_table($pdo, [
    'pedido_itens',
    'pedidos_itens',
    'itens_pedido',
    'itens_pedidos',
    'pedido_produtos',
    'pedidos_produtos'
  ]);

  if (!$itensTable) {
    // fallback final: se contas tem total_fatura (mesmo 0), devolve isso e avisa
    return [
      'conta' => ['id'=>(int)$c['id'], 'status'=>(string)$c['status']],
      'total_fatura' => $totalFatura,
      'total_pago' => $totalPago,
      'warn' => "Não encontrei tabela de itens (ex: pedido_itens). Informe o nome da tabela/colunas para calcular a fatura."
    ];
  }

  // colunas típicas da tabela de itens
  $colPedidoId = pick_first_existing_column($pdo, $itensTable, ['pedido_id', 'pedidos_id', 'id_pedido']);
  if (!$colPedidoId) {
    throw new Exception("Tabela '$itensTable' existe, mas não encontrei coluna de vínculo com pedido (pedido_id/id_pedido).");
  }

  // Melhor caso: itens já tem subtotal/total
  $colSubtotal = pick_first_existing_column($pdo, $itensTable, ['subtotal', 'total', 'valor_total', 'total_item', 'valor']);
  $colQtd      = pick_first_existing_column($pdo, $itensTable, ['qtd', 'quantidade', 'qtde']);
  $colPreco    = pick_first_existing_column($pdo, $itensTable, ['preco', 'valor_unitario', 'vl_unit', 'unitario', 'preco_unit']);

  $exprItem = null;

  if ($colSubtotal) {
    $exprItem = "i.`$colSubtotal`";
  } elseif ($colQtd && $colPreco) {
    $exprItem = "(i.`$colQtd` * i.`$colPreco`)";
  } else {
    throw new Exception("Tabela '$itensTable': não encontrei subtotal/total nem par (quantidade * preço). Colunas esperadas: subtotal|total ou qtd+preco.");
  }

  // filtro de status em pedidos (se existir)
  $hasPedidoStatus = column_exists($pdo, 'pedidos', 'status');
  $statusFilter = "";
  if ($hasPedidoStatus) {
    // Ajuste aqui se seus status forem diferentes
    $statusFilter = "AND p.status IN ('ENTREGUE','FECHADO','OK')";
  }

  // soma itens dos pedidos daquela conta
  $sql = "
    SELECT
      c.id,
      c.status,
      COALESCE(SUM($exprItem), 0) AS total_fatura
    FROM contas c
    JOIN pedidos p ON p.conta_id = c.id
    JOIN `$itensTable` i ON i.`$colPedidoId` = p.id
    WHERE c.id = ?
    $statusFilter
    GROUP BY c.id
    LIMIT 1
  ";
  $st3 = $pdo->prepare($sql);
  $st3->execute([$contaId]);
  $row = $st3->fetch(PDO::FETCH_ASSOC);

  $totalFaturaCalc = (float)($row['total_fatura'] ?? 0);

  // total_pago: se existe na conta, usamos; senão 0
  $totalPagoCalc = $hasTotalPago ? $totalPago : 0.0;

  return [
    'conta' => ['id'=>(int)$c['id'], 'status'=>(string)$c['status']],
    'total_fatura' => $totalFaturaCalc,
    'total_pago' => $totalPagoCalc,
    'debug' => [
      'itens_table' => $itensTable,
      'expr_item' => $exprItem
    ]
  ];
}

/** ===== PIX EMV ===== */
function crc16(string $payload): string {
  $polinomio = 0x1021;
  $resultado = 0xFFFF;
  $len = strlen($payload);

  for ($offset=0; $offset < $len; $offset++) {
    $resultado ^= (ord($payload[$offset]) << 8);
    for ($bit=0; $bit<8; $bit++) {
      if (($resultado & 0x8000) !== 0) {
        $resultado = (($resultado << 1) ^ $polinomio) & 0xFFFF;
      } else {
        $resultado = ($resultado << 1) & 0xFFFF;
      }
    }
  }
  return strtoupper(str_pad(dechex($resultado), 4, '0', STR_PAD_LEFT));
}

function tlv(string $id, string $value): string {
  return $id . str_pad((string)strlen($value), 2, '0', STR_PAD_LEFT) . $value;
}

function pix_payload(array $p): string {
  $chave = (string)$p['chave_pix'];
  $nome  = mb_substr((string)$p['nome'], 0, 25);
  $cidade= mb_substr((string)$p['cidade'], 0, 15);
  $valor = number_format((float)$p['valor'], 2, '.', '');
  $txid  = mb_substr((string)$p['txid'], 0, 35);

  $mai = tlv('00','BR.GOV.BCB.PIX') . tlv('01',$chave);

  $payload =
    tlv('00','01').
    tlv('01','12').
    tlv('26',$mai).
    tlv('52','0000').
    tlv('53','986').
    tlv('54',$valor).
    tlv('58','BR').
    tlv('59',$nome).
    tlv('60',$cidade).
    tlv('62', tlv('05',$txid));

  $payloadSemCrc = $payload . '6304';
  return $payloadSemCrc . crc16($payloadSemCrc);
}

$action = (string)($_GET['action'] ?? '');
if (strpos($action, '&') !== false) $action = explode('&', $action, 2)[0];

/** ===== AÇÕES ===== */

if ($action === 'conta_resumo') {
  must_staff_user_id();

  $contaId = (int)($_GET['conta_id'] ?? 0);
  if ($contaId <= 0) jexit(["ok"=>false, "error"=>"conta_id inválido"], 400);

  try {
    $t = calcular_totais_conta($pdo, $contaId);
    $saldo = max(0, (float)$t['total_fatura'] - (float)$t['total_pago']);

    $resp = [
      "ok" => true,
      "conta" => $t['conta'],
      "total_fatura" => (float)$t['total_fatura'],
      "total_pago" => (float)$t['total_pago'],
      "saldo" => $saldo
    ];

    if (!empty($t['warn'])) $resp['warn'] = $t['warn'];
    // se quiser ver debug, descomente:
    // if (!empty($t['debug'])) $resp['debug'] = $t['debug'];

    jexit($resp);
  } catch (Throwable $e) {
    jexit(["ok"=>false, "error"=>$e->getMessage()], 400);
  }
}

if ($action === 'pix_gerar') {
  $uid = must_staff_user_id();
  $in = json_input();

  $contaId = (int)($in['conta_id'] ?? 0);
  if ($contaId <= 0) jexit(["ok"=>false, "error"=>"conta_id inválido"], 400);

  try {
    $t = calcular_totais_conta($pdo, $contaId);
    $saldo = (float)$t['total_fatura'] - (float)$t['total_pago'];
    if ($saldo <= 0.0001) jexit(["ok"=>false, "error"=>"Conta sem saldo a pagar"], 409);

    // ✅ CONFIG PIX (troque aqui)
    $CHAVE  = 'SUA-CHAVE-PIX-AQUI';
    $NOME   = 'SEU ESTABELECIMENTO';
    $CIDADE = 'SUA CIDADE';

    $txid = 'C'.$contaId.'T'.substr(bin2hex(random_bytes(6)), 0, 12);

    $payload = pix_payload([
      'chave_pix' => $CHAVE,
      'nome' => $NOME,
      'cidade' => $CIDADE,
      'valor' => $saldo,
      'txid' => $txid
    ]);

    $ins = $pdo->prepare("
      INSERT INTO pagamentos_pix
        (conta_id, valor, txid, chave_pix, beneficiario_nome, beneficiario_cidade, payload, copia_cola, status)
      VALUES (?,?,?,?,?,?,?,?,'PENDENTE')
    ");
    $ins->execute([$contaId, $saldo, $txid, $CHAVE, $NOME, $CIDADE, $payload, $payload]);

    jexit([
      "ok" => true,
      "pix" => [
        "id" => (int)$pdo->lastInsertId(),
        "conta_id" => $contaId,
        "valor" => (float)$saldo,
        "txid" => $txid,
        "copia_cola" => $payload
      ]
    ]);
  } catch (Throwable $e) {
    jexit(["ok"=>false, "error"=>$e->getMessage()], 400);
  }
}

if ($action === 'pix_confirmar') {
  $uid = must_staff_user_id();
  $in = json_input();

  $pixId = (int)($in['pix_id'] ?? 0);
  if ($pixId <= 0) jexit(["ok"=>false, "error"=>"pix_id inválido"], 400);

  $pdo->beginTransaction();
  try {
    $st = $pdo->prepare("SELECT * FROM pagamentos_pix WHERE id=? FOR UPDATE");
    $st->execute([$pixId]);
    $p = $st->fetch(PDO::FETCH_ASSOC);
    if (!$p) throw new Exception("PIX não encontrado");
    if ((string)$p['status'] !== 'PENDENTE') throw new Exception("PIX não está pendente");

    $up1 = $pdo->prepare("UPDATE pagamentos_pix SET status='CONFIRMADO', confirmado_em=NOW(), confirmado_por=? WHERE id=?");
    $up1->execute([$uid, $pixId]);

    // total_pago (se existir)
    if (column_exists($pdo, 'contas', 'total_pago')) {
      $up2 = $pdo->prepare("UPDATE contas SET total_pago = total_pago + ? WHERE id=?");
      $up2->execute([(float)$p['valor'], (int)$p['conta_id']]);
    }

    // encerra conta se existir coluna status e total_fatura/total_pago
    if (column_exists($pdo, 'contas', 'status') && column_exists($pdo, 'contas', 'total_fatura') && column_exists($pdo, 'contas', 'total_pago')) {
      $up3 = $pdo->prepare("
        UPDATE contas
        SET status = CASE WHEN (total_fatura - total_pago) <= 0.0001 THEN 'ENCERRADA' ELSE status END
        WHERE id=?
      ");
      $up3->execute([(int)$p['conta_id']]);
    }

    $pdo->commit();
    jexit(["ok"=>true]);
  } catch (Throwable $e) {
    $pdo->rollBack();
    jexit(["ok"=>false, "error"=>$e->getMessage()], 400);
  }
}

jexit(["ok"=>false, "error"=>"Ação inválida"], 400);
