<?php
require_once __DIR__ . "/_bootstrap.php";
header("Content-Type: application/json; charset=utf-8");

$action = $_GET["action"] ?? "";

function json_input(): array {
  // Aceita JSON (fetch com application/json) e também POST tradicional (FormData/x-www-form-urlencoded)
  $raw = file_get_contents("php://input");
  $ct  = (string)($_SERVER["CONTENT_TYPE"] ?? $_SERVER["HTTP_CONTENT_TYPE"] ?? "");

  if ($raw !== "" && stripos($ct, "application/json") !== false) {
    $data = json_decode($raw, true);
    if (is_array($data)) return $data;
  }

  if (!empty($_POST) && is_array($_POST)) return $_POST;

  // fallback: tenta JSON mesmo sem content-type correto
  if ($raw !== "") {
    $data = json_decode($raw, true);
    if (is_array($data)) return $data;
  }

  return [];
}

/* ===================== CHAMAR GARÇOM =====================
   ✅ Preferência: tabela MySQL/MariaDB `chamados_garcom` (mesma usada pelo cliente).
   ✅ Compatibilidade: se a tabela não existir, mantém o fallback antigo por arquivo JSON.

   Endpoints usados pelo front do garçom:
   - GET  api.php?action=listar_chamados&pendentes=1
   - GET  api.php?action=atender_chamado&id=...

   Observação importante:
   - O cliente grava com status='ABERTO'
   - O garçom deve listar status='ABERTO' (pendentes) e marcar como 'ATENDIDO'
*/
// --- Fallback legado (arquivo JSON). Mantido para compatibilidade.
function chamadas_file(): string {
  $tmp = @sys_get_temp_dir();
  if (is_string($tmp) && $tmp !== '' && @is_dir($tmp) && @is_writable($tmp)) {
    return rtrim($tmp, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'lanchonete_chamadas_garcom.json';
  }

  $dir = __DIR__ . DIRECTORY_SEPARATOR . 'data';
  if (!is_dir($dir)) {
    @mkdir($dir, 0777, true);
  }
  return $dir . DIRECTORY_SEPARATOR . 'chamadas_garcom.json';
}

function chamadas_load(): array {
  $file = chamadas_file();
  if (!file_exists($file)) return [];
  $raw = @file_get_contents($file);
  if ($raw === false) return [];
  $data = json_decode($raw, true);
  return is_array($data) ? $data : [];
}

function chamadas_save(array $data): bool {
  $file = chamadas_file();
  $dir = dirname($file);
  if (!is_dir($dir)) @mkdir($dir, 0777, true);

  $fp = @fopen($file, 'c+');
  if (!$fp) return false;

  try {
    if (!flock($fp, LOCK_EX)) { fclose($fp); return false; }
    ftruncate($fp, 0);
    rewind($fp);
    fwrite($fp, json_encode($data, JSON_UNESCAPED_UNICODE));
    fflush($fp);
    flock($fp, LOCK_UN);
    fclose($fp);
    return true;
  } catch (Throwable $e) {
    @flock($fp, LOCK_UN);
    @fclose($fp);
    return false;
  }
}

function table_exists(PDO $pdo, string $table): bool {
  static $cache = [];
  if (isset($cache[$table])) return $cache[$table];
  $st = $pdo->prepare("
    SELECT COUNT(*) c
    FROM information_schema.tables
    WHERE table_schema = DATABASE() AND table_name = ?
  ");
  $st->execute([$table]);
  $cache[$table] = ((int)($st->fetch()["c"] ?? 0) > 0);
  return $cache[$table];
}

function column_exists(PDO $pdo, string $table, string $col): bool {
  static $cache = [];
  $k = $table . "." . $col;
  if (isset($cache[$k])) return $cache[$k];
  $st = $pdo->prepare("
    SELECT COUNT(*) c
    FROM information_schema.columns
    WHERE table_schema = DATABASE()
      AND table_name = ?
      AND column_name = ?
  ");
  $st->execute([$table, $col]);
  $cache[$k] = ((int)($st->fetch()["c"] ?? 0) > 0);
  return $cache[$k];
}

/* ===================== CHAMADOS DE GARÇOM (Arquivo JSON) =====================
   Endpoints esperados por /garcom/index.php:
   - GET  api.php?action=listar_chamados&pendentes=1
   - GET  api.php?action=atender_chamado&id=...
   Endpoint chamado pelo cliente:
   - POST api.php?action=chamar_garcom  body {mesa, conta_id}
*/

function chamadas_cleanup(array $chamados): array {
  // remove atendidos antigos (>= 24h) para não crescer infinito
  $now = time();
  $out = [];
  foreach ($chamados as $c) {
    if (!is_array($c)) continue;
    $at = $c["atendido_ts"] ?? null;
    if ($at && is_numeric($at) && ($now - (int)$at) > 86400) continue;
    $out[] = $c;
  }
  return $out;
}

// --- Preferência: tabela MySQL/MariaDB (mesma do cliente)
function ensure_chamados_table(PDO $pdo): void {
  if (table_exists($pdo, 'chamados_garcom')) return;
  // Não cria automaticamente aqui para não mexer em bancos onde o usuário não quer.
  // O cliente já cria quando necessário.
}

function chamados_db_list(PDO $pdo, int $sinceTs, bool $pendentesOnly): array {
  if (!table_exists($pdo, 'chamados_garcom')) return [];

  $where = [];
  $params = [];
  if ($pendentesOnly) {
    $where[] = "status='ABERTO'";
  }
  if ($sinceTs > 0) {
    // sinceTs é unix timestamp
    $where[] = "UNIX_TIMESTAMP(criado_em) >= ?";
    $params[] = $sinceTs;
  }
  $w = $where ? ('WHERE ' . implode(' AND ', $where)) : '';

  $st = $pdo->prepare("\n    SELECT id, mesa, conta_id, cliente_id, sessao_key, status, criado_em, atendido_em\n    FROM chamados_garcom\n    {$w}\n    ORDER BY id DESC\n    LIMIT 200\n  ");
  $st->execute($params);
  $rows = $st->fetchAll(PDO::FETCH_ASSOC);

  // Normaliza formato para bater com o frontend antigo
  $out = [];
  foreach ($rows as $r) {
    $out[] = [
      'id'         => (string)($r['id'] ?? ''),
      'mesa'       => (int)($r['mesa'] ?? 0),
      'conta_id'   => (int)($r['conta_id'] ?? 0),
      'cliente_id' => (int)($r['cliente_id'] ?? 0),
      'status'     => (string)($r['status'] ?? ''),
      'criado_em'  => (string)($r['criado_em'] ?? ''),
      'criado_ts'  => (int)@strtotime((string)($r['criado_em'] ?? '')),
      'atendido_em'=> (string)($r['atendido_em'] ?? ''),
      'atendido_ts'=> $r['atendido_em'] ? (int)@strtotime((string)$r['atendido_em']) : null,
    ];
  }
  return $out;
}

function chamados_db_atender(PDO $pdo, int $id): bool {
  if ($id <= 0) return false;
  if (!table_exists($pdo, 'chamados_garcom')) return false;
  $st = $pdo->prepare("UPDATE chamados_garcom SET status='ATENDIDO', atendido_em=NOW() WHERE id=? AND status='ABERTO'");
  $st->execute([$id]);
  return ($st->rowCount() > 0);
}

/**
 * GET api.php?action=pedidos
 */
if ($action === "pedidos") {
  try {
    $sql = "
      SELECT
        p.id AS pedido_id,
        p.sessao_seq,
        p.status,
        p.criado_em,
        c.id AS conta_id,
        m.numero AS mesa,
        pr.nome AS produto,
        i.qtd,
        i.preco_unit,
        i.observacao
      FROM pedidos p
      JOIN contas c ON c.id = p.conta_id
      JOIN mesas m ON m.id = c.mesa_id
      JOIN pedido_itens i ON i.pedido_id = p.id
      JOIN produtos pr ON pr.id = i.produto_id
      WHERE c.status = 'ABERTA'
        AND p.status <> 'CANCELADO'
      ORDER BY p.id ASC, i.id ASC
    ";

    $rows = $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);

    $pedidos = [];
    foreach ($rows as $r) {
      $pid = (int)$r["pedido_id"];
      if (!isset($pedidos[$pid])) {
        $pedidos[$pid] = [
          "pedido_id"  => $pid,
          "sessao_seq" => (int)($r["sessao_seq"] ?? 0),
          "status"     => $r["status"] ?? "ENVIADO",
          "criado_em"  => $r["criado_em"] ?? "",
          "mesa"       => (int)($r["mesa"] ?? 0),
          "conta_id"   => (int)($r["conta_id"] ?? 0),
          "itens"      => []
        ];
      }

      $pedidos[$pid]["itens"][] = [
        "produto"     => $r["produto"] ?? "",
        "qtd"         => (int)($r["qtd"] ?? 0),
        "preco_unit"  => (float)($r["preco_unit"] ?? 0),
        "observacao"  => $r["observacao"] ?? ""
      ];
    }

    echo json_encode(["ok" => true, "pedidos" => array_values($pedidos)]);
  } catch (Throwable $e) {
    http_response_code(500);
    echo json_encode(["ok" => false, "error" => "Erro interno: " . $e->getMessage()]);
  }
  exit;
}

/**
 * POST api.php?action=status
 * body {pedido_id, status}
 */
if ($action === "status") {
  $data = json_input();

  $pedidoId = (int)($data["pedido_id"] ?? 0);
  $status   = strtoupper(trim($data["status"] ?? ""));

  $validos = ["ACEITO", "EM_PREPARO", "ENTREGUE"];
  if ($pedidoId <= 0 || !in_array($status, $validos, true)) {
    http_response_code(400);
    echo json_encode(["ok"=>false, "error"=>"Dados inválidos"]);
    exit;
  }

  $st = $pdo->prepare("SELECT id, status FROM pedidos WHERE id=? LIMIT 1");
  $st->execute([$pedidoId]);
  $p = $st->fetch(PDO::FETCH_ASSOC);

  if (!$p) {
    http_response_code(404);
    echo json_encode(["ok"=>false, "error"=>"Pedido não encontrado"]);
    exit;
  }

  $ordem = ["ENVIADO"=>1, "ACEITO"=>2, "EM_PREPARO"=>3, "ENTREGUE"=>4];
  $atual = $ordem[$p["status"]] ?? 0;
  $novo  = $ordem[$status] ?? 0;

  if ($novo <= $atual) {
    echo json_encode(["ok"=>true]);
    exit;
  }

  if ($status === "ENTREGUE") {
    $up = $pdo->prepare("UPDATE pedidos SET status='ENTREGUE', entregue_em=NOW() WHERE id=?");
    $up->execute([$pedidoId]);
  } else {
    $up = $pdo->prepare("UPDATE pedidos SET status=? WHERE id=?");
    $up->execute([$status, $pedidoId]);
  }

  echo json_encode(["ok"=>true]);
  exit;
}

/**
 * ✅ POST api.php?action=recusar
 * body {pedido_id, motivo}
 */
if ($action === "recusar") {
  $data = json_input();
  $pedidoId = (int)($data["pedido_id"] ?? 0);
  $motivo   = trim((string)($data["motivo"] ?? ""));

  if ($pedidoId <= 0 || mb_strlen($motivo) < 3) {
    http_response_code(400);
    echo json_encode(["ok"=>false, "error"=>"Informe o motivo da recusa (mín. 3 caracteres)."]);
    exit;
  }
  if (mb_strlen($motivo) > 255) $motivo = mb_substr($motivo, 0, 255);

  $st = $pdo->prepare("SELECT id, status FROM pedidos WHERE id=? LIMIT 1");
  $st->execute([$pedidoId]);
  $p = $st->fetch(PDO::FETCH_ASSOC);

  if (!$p) {
    http_response_code(404);
    echo json_encode(["ok"=>false, "error"=>"Pedido não encontrado."]);
    exit;
  }

  $curStatus = strtoupper(trim((string)($p["status"] ?? "")));

  if (in_array($curStatus, ["ENTREGUE","CANCELADO"], true)) {
    http_response_code(400);
    echo json_encode(["ok"=>false, "error"=>"Não é possível recusar: pedido já finalizado."]);
    exit;
  }

  try {
    // se tiver colunas na pedidos, grava direto lá
    $hasMotivo = column_exists($pdo, "pedidos", "recusado_motivo");
    $hasEm     = column_exists($pdo, "pedidos", "recusado_em");

    if ($hasMotivo && $hasEm) {
      $up = $pdo->prepare("
        UPDATE pedidos
        SET status='CANCELADO', recusado_motivo=?, recusado_em=NOW()
        WHERE id=?
        LIMIT 1
      ");
      $up->execute([$motivo, $pedidoId]);
    } else {
      // fallback seguro: tabela auxiliar
      if (!table_exists($pdo, "pedido_recusas")) {
        $pdo->exec("
          CREATE TABLE pedido_recusas (
            id INT AUTO_INCREMENT PRIMARY KEY,
            pedido_id INT NOT NULL,
            motivo VARCHAR(255) NOT NULL,
            criado_em DATETIME NOT NULL,
            INDEX (pedido_id)
          ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
        ");
      }

      $pdo->beginTransaction();
      $up = $pdo->prepare("UPDATE pedidos SET status='CANCELADO' WHERE id=? LIMIT 1");
      $up->execute([$pedidoId]);

      $ins = $pdo->prepare("INSERT INTO pedido_recusas (pedido_id, motivo, criado_em) VALUES (?,?,NOW())");
      $ins->execute([$pedidoId, $motivo]);

      $pdo->commit();
    }

    echo json_encode(["ok"=>true]);
  } catch (Throwable $e) {
    if ($pdo->inTransaction()) $pdo->rollBack();
    http_response_code(500);
    echo json_encode(["ok"=>false, "error"=>"Erro ao recusar: " . $e->getMessage()]);
  }
  exit;
}


/**
 * ✅ GET api.php?action=recusa_motivo&pedido_id=123
 * Retorna o motivo de recusa para o cliente.
 */
if ($action === "recusa_motivo") {
  $pedidoId = (int)($_GET["pedido_id"] ?? 0);
  if ($pedidoId <= 0) {
    http_response_code(400);
    echo json_encode(["ok"=>false, "error"=>"pedido_id inválido."]);
    exit;
  }

  try {
    // 1) se a coluna existir em pedidos, pega de lá
    if (column_exists($pdo, "pedidos", "recusado_motivo")) {
      $st = $pdo->prepare("SELECT recusado_motivo AS motivo FROM pedidos WHERE id=? LIMIT 1");
      $st->execute([$pedidoId]);
      $row = $st->fetch(PDO::FETCH_ASSOC);
      $motivo = trim((string)($row["motivo"] ?? ""));
      echo json_encode(["ok"=>true, "pedido_id"=>$pedidoId, "motivo"=>$motivo]);
      exit;
    }

    // 2) fallback: tabela auxiliar
    if (table_exists($pdo, "pedido_recusas")) {
      $st = $pdo->prepare("SELECT motivo FROM pedido_recusas WHERE pedido_id=? ORDER BY id DESC LIMIT 1");
      $st->execute([$pedidoId]);
      $row = $st->fetch(PDO::FETCH_ASSOC);
      $motivo = trim((string)($row["motivo"] ?? ""));
      echo json_encode(["ok"=>true, "pedido_id"=>$pedidoId, "motivo"=>$motivo]);
      exit;
    }

    echo json_encode(["ok"=>true, "pedido_id"=>$pedidoId, "motivo"=>""]);
  } catch (Throwable $e) {
    http_response_code(500);
    echo json_encode(["ok"=>false, "error"=>"Erro ao buscar motivo: " . $e->getMessage()]);
  }
  exit;
}


/**
 * GET api.php?action=listar_chamados&pendentes=1
 * Retorna chamados do "Chamar Garçom" (cliente).
 */
if ($action === "listar_chamados") {
  $since = (int)($_GET["since_ts"] ?? 0);
  $pendentes = (int)($_GET["pendentes"] ?? 1);

  // ✅ Preferir banco (tabela chamados_garcom) se existir
  if (table_exists($pdo, 'chamados_garcom')) {
    $rows = chamados_db_list($pdo, $since, ($pendentes === 1));
    echo json_encode(["ok" => true, "chamados" => $rows], JSON_UNESCAPED_UNICODE);
    exit;
  }

  // Fallback: arquivo JSON (legado)
  $calls = chamadas_load();
  $out = [];
  foreach ($calls as $c) {
    $ts = (int)($c["criado_ts"] ?? 0);
    if ($since > 0 && $ts > 0 && $ts < $since) continue;
    $isPendente = empty($c["atendido_em"]);
    if ($pendentes === 1 && !$isPendente) continue;
    $out[] = $c;
  }
  usort($out, function($a,$b){
    return (int)($b["criado_ts"] ?? 0) <=> (int)($a["criado_ts"] ?? 0);
  });
  echo json_encode(["ok" => true, "chamados" => $out], JSON_UNESCAPED_UNICODE);
  exit;
}

/**
 * GET api.php?action=atender_chamado&id=...
 */
if ($action === "atender_chamado") {
  $idRaw = (string)($_GET["id"] ?? "");
  if ($idRaw === "") {
    http_response_code(400);
    echo json_encode(["ok" => false, "error" => "id inválido"], JSON_UNESCAPED_UNICODE);
    exit;
  }

  // ✅ Preferir banco (tabela chamados_garcom) se existir
  if (table_exists($pdo, 'chamados_garcom')) {
    $id = (int)$idRaw;
    if ($id <= 0) {
      http_response_code(400);
      echo json_encode(["ok" => false, "error" => "id inválido"], JSON_UNESCAPED_UNICODE);
      exit;
    }
    $ok = chamados_db_atender($pdo, $id);
    echo json_encode(["ok" => true, "updated" => $ok], JSON_UNESCAPED_UNICODE);
    exit;
  }

  // Fallback: arquivo JSON (legado)
  $id = $idRaw;
  $calls = chamadas_load();
  $found = false;
  foreach ($calls as &$c) {
    if (($c["id"] ?? "") === $id) {
      if (empty($c["atendido_em"])) {
        $c["atendido_em"] = date('Y-m-d H:i:s');
      }
      $found = true;
      break;
    }
  }
  unset($c);

  if (!$found) {
    http_response_code(404);
    echo json_encode(["ok" => false, "error" => "Chamada não encontrada"], JSON_UNESCAPED_UNICODE);
    exit;
  }

  if (!chamadas_save($calls)) {
    http_response_code(500);
    echo json_encode(["ok" => false, "error" => "Não foi possível atualizar a chamada"], JSON_UNESCAPED_UNICODE);
    exit;
  }

  echo json_encode(["ok" => true], JSON_UNESCAPED_UNICODE);
  exit;
}



/**
 * GET api.php?action=mesas_pendentes
 * Lista contas/mesas aguardando liberação do garçom
 *
 * Estratégia compatível:
 * - Se existir coluna contas.liberada (TINYINT), usa liberada=0
 * - Senão, se existir contas.liberada_em (DATETIME), usa liberada_em IS NULL
 * - Senão, usa status='ABERTA'
 */



// ===== Liberação de mesa/conta (garçom) =====
// Regras:
// - A liberação "válida" para o cliente pedir é sempre quando contas.liberada=1 (se existir) OU contas.liberada_em IS NOT NULL (se existir) OU contas_liberacoes.liberada=1.
// - Para suportar "RECUSADA" sem bagunçar sua tabela contas, usamos SEMPRE a tabela contas_liberacoes (criamos automaticamente).
//   - liberada=0 (PENDENTE) | 1 (LIBERADA) | 2 (RECUSADA)

function contas_liberacao_mode(PDO $pdo): string {
  // retorna: 'flag' | 'ts' | 'table'
  if (column_exists($pdo, "contas", "liberada")) return "flag";
  if (column_exists($pdo, "contas", "liberada_em")) return "ts";
  return "table";
}

function ensure_contas_liberacoes(PDO $pdo): void {
  if (table_exists($pdo, 'contas_liberacoes')) return;
  $pdo->exec("
    CREATE TABLE IF NOT EXISTS contas_liberacoes (
      conta_id INT NOT NULL PRIMARY KEY,
      liberada TINYINT(2) NOT NULL DEFAULT 0,      /* 0 pendente | 1 liberada | 2 recusada */
      liberada_em DATETIME NULL,
      liberada_por INT NULL,
      recusada_em DATETIME NULL,
      recusada_por INT NULL,
      criado_em DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
      atualizado_em DATETIME NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
  ");
}

function liberacao_status(PDO $pdo, int $contaId): int {
  ensure_contas_liberacoes($pdo);

  // prioridade: tabela (suporta RECUSADA)
  $st = $pdo->prepare("SELECT liberada FROM contas_liberacoes WHERE conta_id=? LIMIT 1");
  $st->execute([$contaId]);
  $r = $st->fetch(PDO::FETCH_ASSOC);
  if ($r) return (int)($r['liberada'] ?? 0);

  // se não tem registro, tenta inferir pela tabela contas
  $mode = contas_liberacao_mode($pdo);
  if ($mode === 'flag') {
    $s2 = $pdo->prepare("SELECT COALESCE(liberada,0) AS liberada FROM contas WHERE id=? LIMIT 1");
    $s2->execute([$contaId]);
    $rr = $s2->fetch(PDO::FETCH_ASSOC);
    return ((int)($rr['liberada'] ?? 0) === 1) ? 1 : 0;
  }
  if ($mode === 'ts') {
    $s2 = $pdo->prepare("SELECT liberada_em FROM contas WHERE id=? LIMIT 1");
    $s2->execute([$contaId]);
    $rr = $s2->fetch(PDO::FETCH_ASSOC);
    return (!empty($rr['liberada_em'])) ? 1 : 0;
  }
  return 0;
}

function upsert_liberacao(PDO $pdo, int $contaId, int $status, ?int $staffId): void {
  ensure_contas_liberacoes($pdo);

  $st = $pdo->prepare("UPDATE contas_liberacoes SET liberada=?, atualizado_em=NOW(),
    liberada_em=IF(?, NOW(), liberada_em),
    liberada_por=IF(?, ?, liberada_por),
    recusada_em=IF(?, NOW(), recusada_em),
    recusada_por=IF(?, ?, recusada_por)
    WHERE conta_id=?");
  $isLiberar = ($status === 1) ? 1 : 0;
  $isRecusar = ($status === 2) ? 1 : 0;
  $st->execute([$status, $isLiberar, $isLiberar, $staffId, $isRecusar, $isRecusar, $staffId, $contaId]);

  if ($st->rowCount() === 0) {
    $ins = $pdo->prepare("
      INSERT INTO contas_liberacoes (conta_id, liberada, liberada_em, liberada_por, recusada_em, recusada_por, atualizado_em)
      VALUES (?,
        ?,
        IF(?, NOW(), NULL),
        IF(?, ?, NULL),
        IF(?, NOW(), NULL),
        IF(?, ?, NULL),
        NOW()
      )
    ");
    $ins->execute([$contaId, $status, $isLiberar, $isLiberar, $staffId, $isRecusar, $isRecusar, $staffId]);
  }
}


if ($action === "mesas_pendentes") {
  try{
    // garante tabela (para suportar RECUSADA mesmo quando contas.liberada existe)
    ensure_contas_liberacoes($pdo);

    // base: contas abertas e NÃO liberadas (p/ cliente pedir)
    // - se existir contas.liberada: liberada=0
    // - senão se existir liberada_em: IS NULL
    // - senão: usa a tabela contas_liberacoes (liberada!=1)
    $mode = contas_liberacao_mode($pdo);

    // cliente (opcional): pega 1 cliente da conta (ATIVO primeiro, senão PENDENTE)
    $hasCP = table_exists($pdo, 'conta_participantes');

    if ($mode === "flag") {
      if ($hasCP) {
        $sql = "
          SELECT
            c.id AS conta_id,
            m.numero AS mesa,
            c.aberta_em,
            COALESCE(clib.liberada,0) AS liberacao_status,
            cl.nome AS cliente_nome,
            cl.celular AS cliente_celular
          FROM contas c
          JOIN mesas m ON m.id = c.mesa_id
          LEFT JOIN contas_liberacoes clib ON clib.conta_id = c.id
          LEFT JOIN clientes cl ON cl.id = (
            SELECT cp.cliente_id
            FROM conta_participantes cp
            WHERE cp.conta_id = c.id AND cp.status IN ('ATIVO','PENDENTE')
            ORDER BY (cp.status='ATIVO') DESC, cp.id ASC
            LIMIT 1
          )
          WHERE c.status='ABERTA'
            AND COALESCE(c.liberada,0)=0
          ORDER BY c.id ASC
          LIMIT 200
        ";
      } else {
        $sql = "
          SELECT
            c.id AS conta_id,
            m.numero AS mesa,
            c.aberta_em,
            COALESCE(clib.liberada,0) AS liberacao_status,
            NULL AS cliente_nome,
            NULL AS cliente_celular
          FROM contas c
          JOIN mesas m ON m.id = c.mesa_id
          LEFT JOIN contas_liberacoes clib ON clib.conta_id = c.id
          WHERE c.status='ABERTA'
            AND COALESCE(c.liberada,0)=0
          ORDER BY c.id ASC
          LIMIT 200
        ";
      }
      $rows = $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
    } elseif ($mode === "ts") {
      if ($hasCP) {
        $sql = "
          SELECT
            c.id AS conta_id,
            m.numero AS mesa,
            c.aberta_em,
            COALESCE(clib.liberada,0) AS liberacao_status,
            cl.nome AS cliente_nome,
            cl.celular AS cliente_celular
          FROM contas c
          JOIN mesas m ON m.id = c.mesa_id
          LEFT JOIN contas_liberacoes clib ON clib.conta_id = c.id
          LEFT JOIN clientes cl ON cl.id = (
            SELECT cp.cliente_id
            FROM conta_participantes cp
            WHERE cp.conta_id = c.id AND cp.status IN ('ATIVO','PENDENTE')
            ORDER BY (cp.status='ATIVO') DESC, cp.id ASC
            LIMIT 1
          )
          WHERE c.status='ABERTA'
            AND c.liberada_em IS NULL
          ORDER BY c.id ASC
          LIMIT 200
        ";
      } else {
        $sql = "
          SELECT
            c.id AS conta_id,
            m.numero AS mesa,
            c.aberta_em,
            COALESCE(clib.liberada,0) AS liberacao_status,
            NULL AS cliente_nome,
            NULL AS cliente_celular
          FROM contas c
          JOIN mesas m ON m.id = c.mesa_id
          LEFT JOIN contas_liberacoes clib ON clib.conta_id = c.id
          WHERE c.status='ABERTA'
            AND c.liberada_em IS NULL
          ORDER BY c.id ASC
          LIMIT 200
        ";
      }
      $rows = $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
    } else {
      // modo table puro
      if ($hasCP) {
        $sql = "
          SELECT
            c.id AS conta_id,
            m.numero AS mesa,
            c.aberta_em,
            COALESCE(clib.liberada,0) AS liberacao_status,
            cl.nome AS cliente_nome,
            cl.celular AS cliente_celular
          FROM contas c
          JOIN mesas m ON m.id = c.mesa_id
          LEFT JOIN contas_liberacoes clib ON clib.conta_id = c.id
          LEFT JOIN clientes cl ON cl.id = (
            SELECT cp.cliente_id
            FROM conta_participantes cp
            WHERE cp.conta_id = c.id AND cp.status IN ('ATIVO','PENDENTE')
            ORDER BY (cp.status='ATIVO') DESC, cp.id ASC
            LIMIT 1
          )
          WHERE c.status='ABERTA'
            AND COALESCE(clib.liberada,0) <> 1
          ORDER BY c.id ASC
          LIMIT 200
        ";
      } else {
        $sql = "
          SELECT
            c.id AS conta_id,
            m.numero AS mesa,
            c.aberta_em,
            COALESCE(clib.liberada,0) AS liberacao_status,
            NULL AS cliente_nome,
            NULL AS cliente_celular
          FROM contas c
          JOIN mesas m ON m.id = c.mesa_id
          LEFT JOIN contas_liberacoes clib ON clib.conta_id = c.id
          WHERE c.status='ABERTA'
            AND COALESCE(clib.liberada,0) <> 1
          ORDER BY c.id ASC
          LIMIT 200
        ";
      }
      $rows = $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
    }

    echo json_encode(["ok"=>true, "mesas"=>$rows, "mode"=>$mode], JSON_UNESCAPED_UNICODE);
  }catch(Throwable $e){
    http_response_code(500);
    echo json_encode(["ok"=>false, "error"=>"Erro interno: ".$e->getMessage()], JSON_UNESCAPED_UNICODE);
  }
  exit;
}


if ($action === "liberar_mesa") {
  try{
    $data = json_input();
    $contaId = (int)($data["conta_id"] ?? 0);
    if ($contaId <= 0) {
      http_response_code(400);
      echo json_encode(["ok"=>false, "error"=>"conta_id inválido"], JSON_UNESCAPED_UNICODE);
      exit;
    }

    // valida conta
    $st = $pdo->prepare("SELECT id, status FROM contas WHERE id=? LIMIT 1");
    $st->execute([$contaId]);
    $c = $st->fetch(PDO::FETCH_ASSOC);
    if (!$c) {
      http_response_code(404);
      echo json_encode(["ok"=>false, "error"=>"Conta não encontrada"], JSON_UNESCAPED_UNICODE);
      exit;
    }
    if (($c["status"] ?? "") !== "ABERTA") {
      http_response_code(403);
      echo json_encode(["ok"=>false, "error"=>"Conta não está ABERTA"], JSON_UNESCAPED_UNICODE);
      exit;
    }

    // marca liberada no "gatilho" principal (contas.*), se existir
    $mode = contas_liberacao_mode($pdo);
    if ($mode === "flag") {
      // garante que não fica "2" aqui: liberada é só 0/1
      $up = $pdo->prepare("UPDATE contas SET liberada=1 WHERE id=?");
      $up->execute([$contaId]);
    } elseif ($mode === "ts") {
      $up = $pdo->prepare("UPDATE contas SET liberada_em=NOW() WHERE id=?");
      $up->execute([$contaId]);
    }

    // registra/atualiza na tabela auxiliar (suporta RECUSADA e histórico)
    $staffId = isset($_SESSION["staff_id"]) ? (int)$_SESSION["staff_id"] : null;
    upsert_liberacao($pdo, $contaId, 1, $staffId);

    echo json_encode(["ok"=>true], JSON_UNESCAPED_UNICODE);
  }catch(Throwable $e){
    http_response_code(500);
    echo json_encode(["ok"=>false, "error"=>"Erro interno: ".$e->getMessage()], JSON_UNESCAPED_UNICODE);
  }
  exit;
}

if ($action === "recusar_liberacao") {
  try{
    $data = json_input();
    $contaId = (int)($data["conta_id"] ?? 0);
    if ($contaId <= 0) {
      http_response_code(400);
      echo json_encode(["ok"=>false, "error"=>"conta_id inválido"], JSON_UNESCAPED_UNICODE);
      exit;
    }

    // valida conta
    $st = $pdo->prepare("SELECT id, status FROM contas WHERE id=? LIMIT 1");
    $st->execute([$contaId]);
    $c = $st->fetch(PDO::FETCH_ASSOC);
    if (!$c) {
      http_response_code(404);
      echo json_encode(["ok"=>false, "error"=>"Conta não encontrada"], JSON_UNESCAPED_UNICODE);
      exit;
    }
    if (($c["status"] ?? "") !== "ABERTA") {
      http_response_code(403);
      echo json_encode(["ok"=>false, "error"=>"Conta não está ABERTA"], JSON_UNESCAPED_UNICODE);
      exit;
    }

    // importante: NÃO marcar contas.liberada=2 (isso quebrava a listagem)
    // mantém como "não liberada" no gatilho principal
    $mode = contas_liberacao_mode($pdo);
    if ($mode === "flag") {
      $up = $pdo->prepare("UPDATE contas SET liberada=0 WHERE id=?");
      $up->execute([$contaId]);
    } elseif ($mode === "ts") {
      $up = $pdo->prepare("UPDATE contas SET liberada_em=NULL WHERE id=?");
      $up->execute([$contaId]);
    }

    $staffId = isset($_SESSION["staff_id"]) ? (int)$_SESSION["staff_id"] : null;
    upsert_liberacao($pdo, $contaId, 2, $staffId);

    echo json_encode(["ok"=>true], JSON_UNESCAPED_UNICODE);
  }catch(Throwable $e){
    http_response_code(500);
    echo json_encode(["ok"=>false, "error"=>"Erro interno: ".$e->getMessage()], JSON_UNESCAPED_UNICODE);
  }
  exit;
}

http_response_code(404);
echo json_encode(["ok"=>false, "error"=>"Ação não encontrada"]);
