<?php
require_once __DIR__ . '/../src/db.php';
require_once __DIR__ . '/../src/helpers.php';

session_start_safe();
$op = $_GET['op'] ?? $_POST['op'] ?? '';

function json_out($arr)
{
  header('Content-Type: application/json; charset=utf-8');
  echo json_encode($arr, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
  exit;
}

/** Exige ser OPERADOR para rotas administrativas */
function require_operador(): void
{
  session_start_safe();
  if (($_SESSION['tipo'] ?? '') !== 'operador') {
    http_response_code(403);
    echo 'forbidden';
    exit;
  }
}

/* =======================================================================
   HELPERS DE UPLOAD
   ======================================================================= */

/* ---------------- Upload de FOTO do usuário ---------------- */
function users_upload_dir(): array
{
  $dir = __DIR__ . '/uploads/users';
  if (!is_dir($dir)) {
    @mkdir($dir, 0777, true);
  }
  $base = '/arapiraca/uploads/users';
  return [$dir, $base];
}
function save_user_photo(array $file, ?string $oldRelativePath): ?string
{
  if (($file['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) return $oldRelativePath;
  if (($file['error'] ?? UPLOAD_ERR_OK) !== UPLOAD_ERR_OK) throw new RuntimeException('Falha no upload.');
  if ($file['size'] > 2 * 1024 * 1024) throw new RuntimeException('Arquivo maior que 2MB.');

  $info = @getimagesize($file['tmp_name']);
  if (!$info) throw new RuntimeException('Arquivo não é imagem válida.');
  $ext = match ($info['mime'] ?? '') {
    'image/jpeg' => 'jpg',
    'image/png'  => 'png',
    'image/webp' => 'webp',
    default      => null,
  };
  if (!$ext) throw new RuntimeException('Formato não suportado (JPG/PNG/WebP).');

  [$dir, $base] = users_upload_dir();
  $name = uniqid('u_', true) . '.' . $ext;
  $dest = $dir . '/' . $name;
  if (!@move_uploaded_file($file['tmp_name'], $dest)) {
    throw new RuntimeException('Não foi possível salvar a imagem.');
  }

  if ($oldRelativePath) {
    $oldAbs = __DIR__ . '/' . ltrim($oldRelativePath, '/\\');
    if (str_starts_with($oldAbs, __DIR__ . '/uploads/users') && file_exists($oldAbs)) {
      @unlink($oldAbs);
    }
  }
  return 'uploads/users/' . $name;
}

/* ---------------- Upload de PDF de LEIS ---------------- */
function laws_upload_dir(): array
{
  $dir = __DIR__ . '/uploads/leis';
  if (!is_dir($dir)) {
    @mkdir($dir, 0777, true);
  }
  $base = '/arapiraca/uploads/leis';
  return [$dir, $base];
}
function save_law_pdf(array $file, ?string $oldRelativePath): ?string
{
  if (($file['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) return $oldRelativePath;
  if (($file['error'] ?? UPLOAD_ERR_OK) !== UPLOAD_ERR_OK) throw new RuntimeException('Falha no upload de PDF.');
  if ($file['size'] > 20 * 1024 * 1024) throw new RuntimeException('PDF maior que 20MB.');

  $finfo = finfo_open(FILEINFO_MIME_TYPE);
  $mime  = finfo_file($finfo, $file['tmp_name']);
  finfo_close($finfo);
  if ($mime !== 'application/pdf') throw new RuntimeException('Apenas PDF é permitido.');

  [$dir, $base] = laws_upload_dir();
  $name = uniqid('lei_', true) . '.pdf';
  $dest = $dir . '/' . $name;
  if (!@move_uploaded_file($file['tmp_name'], $dest)) {
    throw new RuntimeException('Não foi possível salvar o PDF.');
  }

  if ($oldRelativePath) {
    $oldAbs = __DIR__ . '/' . ltrim($oldRelativePath, '/\\');
    if (str_starts_with($oldAbs, __DIR__ . '/uploads/leis') && file_exists($oldAbs)) {
      @unlink($oldAbs);
    }
  }
  return 'uploads/leis/' . $name;
}

/* ---------------- Upload de PDF de MATÉRIAS ---------------- */
function materias_upload_dir(): array
{
  $dir = __DIR__ . '/uploads/materias';
  if (!is_dir($dir)) {
    @mkdir($dir, 0777, true);
  }
  $base = '/arapiraca/uploads/materias';
  return [$dir, $base];
}
function save_materia_pdf(array $file, ?string $oldRelativePath): ?string
{
  if (($file['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) return $oldRelativePath;
  if (($file['error'] ?? UPLOAD_ERR_OK) !== UPLOAD_ERR_OK) throw new RuntimeException('Falha no upload de PDF.');
  if ($file['size'] > 20 * 1024 * 1024) throw new RuntimeException('PDF maior que 20MB.');

  $finfo = finfo_open(FILEINFO_MIME_TYPE);
  $mime  = finfo_file($finfo, $file['tmp_name']);
  finfo_close($finfo);
  if ($mime !== 'application/pdf') throw new RuntimeException('Apenas PDF é permitido.');

  [$dir, $base] = materias_upload_dir();
  $name = uniqid('mat_', true) . '.pdf';
  $dest = $dir . '/' . $name;
  if (!@move_uploaded_file($file['tmp_name'], $dest)) {
    throw new RuntimeException('Não foi possível salvar o PDF.');
  }

  if ($oldRelativePath) {
    $oldAbs = __DIR__ . '/' . ltrim($oldRelativePath, '/\\');
    if (str_starts_with($oldAbs, __DIR__ . '/uploads/materias') && file_exists($oldAbs)) {
      @unlink($oldAbs);
    }
  }
  return 'uploads/materias/' . $name;
}

/* ---------------- Upload de PDF de ATAS ---------------- */
function atas_upload_dir(): array
{
  $dir = __DIR__ . '/uploads/atas';
  if (!is_dir($dir)) {
    @mkdir($dir, 0777, true);
  }
  $base = '/arapiraca/uploads/atas';
  return [$dir, $base];
}
function save_ata_pdf(array $file, ?string $oldRelativePath): ?string
{
  if (($file['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) return $oldRelativePath;
  if (($file['error'] ?? UPLOAD_ERR_OK) !== UPLOAD_ERR_OK) throw new RuntimeException('Falha no upload de PDF.');
  if ($file['size'] > 20 * 1024 * 1024) throw new RuntimeException('PDF maior que 20MB.');

  $finfo = finfo_open(FILEINFO_MIME_TYPE);
  $mime  = finfo_file($finfo, $file['tmp_name']);
  finfo_close($finfo);
  if ($mime !== 'application/pdf') throw new RuntimeException('Apenas PDF é permitido.');

  [$dir, $base] = atas_upload_dir();

  // padrão: nome seguro com timestamp + nome original sanitizado
  $safe  = preg_replace('/[^a-z0-9\.\-_]/i', '_', $file['name']);
  $name  = date('Ymd_His') . '_' . $safe;
  $dest  = $dir . '/' . $name;

  if (!@move_uploaded_file($file['tmp_name'], $dest)) {
    throw new RuntimeException('Não foi possível salvar o PDF.');
  }

  if ($oldRelativePath) {
    $oldAbs = __DIR__ . '/' . ltrim($oldRelativePath, '/\\');
    if (str_starts_with($oldAbs, __DIR__ . '/uploads/atas') && file_exists($oldAbs)) {
      @unlink($oldAbs);
    }
  }
  return 'uploads/atas/' . $name;
}

/* ----------------------- LEITURA (painel público) ----------------------- */
/* Persistência simples em arquivo por sessão: uploads/runtime/leitura_s{sid}.json */
function leitura_runtime_dir(): string
{
  $dir = __DIR__ . '/uploads/runtime';
  if (!is_dir($dir)) {
    @mkdir($dir, 0777, true);
  }
  return $dir;
}
function leitura_state_file(int $sessao_id): string
{
  return leitura_runtime_dir() . '/leitura_s' . $sessao_id . '.json';
}
function leitura_get(int $sessao_id): ?array
{
  $file = leitura_state_file($sessao_id);
  if (!is_file($file)) return null;
  $json = @file_get_contents($file);
  $data = @json_decode($json, true);
  if (!is_array($data) || !isset($data['sm_id'])) return null;
  return ['sm_id' => (int)$data['sm_id'], 'started_at' => (int)($data['started_at'] ?? time())];
}
function leitura_set(int $sessao_id, int $sm_id): void
{
  $file = leitura_state_file($sessao_id);
  $payload = json_encode(['sm_id' => $sm_id, 'started_at' => time()], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
  @file_put_contents($file, $payload);
}
function leitura_clear(int $sessao_id): void
{
  $file = leitura_state_file($sessao_id);
  if (is_file($file)) @unlink($file);
}

/* ----------------------- APARTE (estado runtime) ----------------------- */
/* Guarda info temporária do aparte para cada sessão: uploads/runtime/aparte_s{sid}.json */
function aparte_state_file(int $sessao_id): string
{
  return leitura_runtime_dir() . '/aparte_s' . $sessao_id . '.json';
}

function aparte_get(int $sessao_id): ?array
{
  $file = aparte_state_file($sessao_id);
  if (!is_file($file)) return null;
  $json = @file_get_contents($file);
  $data = @json_decode($json, true);
  if (!is_array($data) || empty($data['principal_id']) || empty($data['aparte_id'])) {
    return null;
  }
  $data['principal_id']       = (int)$data['principal_id'];
  $data['aparte_id']          = (int)$data['aparte_id'];
  $data['aparte_started_at']  = (int)($data['aparte_started_at'] ?? time());
  $data['principal_restante'] = (int)($data['principal_restante'] ?? 0);
  $data['aparte_vereador_id'] = (int)($data['aparte_vereador_id'] ?? 0);
  return $data;
}

function aparte_set(int $sessao_id, int $principal_id, int $principal_restante_seg, int $aparte_id, int $aparte_vereador_id): void
{
  $file = aparte_state_file($sessao_id);
  $payload = [
    'principal_id'         => $principal_id,
    'principal_restante'   => $principal_restante_seg, // em segundos
    'aparte_id'            => $aparte_id,
    'aparte_vereador_id'   => $aparte_vereador_id,
    'aparte_started_at'    => time(),
  ];
  @file_put_contents($file, json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
}

function aparte_clear(int $sessao_id): void
{
  $file = aparte_state_file($sessao_id);
  if (is_file($file)) @unlink($file);
}


/* ======================== ROTAS ======================== */
switch ($op) {

  /* -------- Sessão do usuário -------- */
  case 'logout':
    // Segurança: não desloga em requisições GET "acidentais"
    if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
      http_response_code(405);
      echo 'method not allowed';
      exit;
    }

    logout_user();
    header('Location:/arapiraca/admin_login.php');
    exit;


    /* -------- Ações do operador (sessões e matérias) -------- */
  case 'iniciar_quorum':
    require_operador();
    $sid = (int)($_GET['sessao_id'] ?? 0);
    if (!$sid) exit('missing sessao');

    $pdo->prepare("UPDATE sessoes SET status='ativa' WHERE id=:id")->execute([':id' => $sid]);

    $vereadores = $pdo->query("SELECT id FROM usuarios WHERE tipo_usuario='vereador' AND ativo=1")->fetchAll();
    foreach ($vereadores as $v) {
      $pdo->prepare("INSERT IGNORE INTO quorum (sessao_id, vereador_id, presente)
                       VALUES (:s,:v,0)")
        ->execute([':s' => $sid, ':v' => $v['id']]);
    }
    header('Location:/arapiraca/admin_sessao_nova.php?id=' . $sid);
    exit;

  case 'encerrar_sessao':
    require_operador();
    $sid = (int)($_GET['sessao_id'] ?? 0);
    if (!$sid) exit('missing');
    $pdo->prepare("UPDATE sessoes SET status='encerrada' WHERE id=:id")->execute([':id' => $sid]);
    leitura_clear($sid);
    header('Location:/arapiraca/admin.php');
    exit;

  case 'iniciar_votacao':
    require_operador();
    $id  = (int)($_GET['id'] ?? 0);        // id de sessao_materias
    $sid = (int)($_GET['sessao_id'] ?? 0);
    if (!$id || !$sid) exit('missing');

    // fecha qualquer votação aberta nessa sessão
    $pdo->prepare("UPDATE sessao_materias
                   SET status='finalizada'
                   WHERE sessao_id=:s AND status='votacao_aberta'")
      ->execute([':s' => $sid]);

    // abre a escolhida
    $pdo->prepare("UPDATE sessao_materias SET status='votacao_aberta' WHERE id=:id AND sessao_id=:s")
      ->execute([':id' => $id, ':s' => $sid]);

    // encerra leitura ligada
    leitura_clear($sid);

    header('Location:/arapiraca/admin_materia_nova.php?sessao=' . $sid);
    exit;

  case 'encerrar_votacao':
    require_operador();
    $id  = (int)($_GET['id'] ?? 0);        // id de sessao_materias
    $sid = (int)($_GET['sessao_id'] ?? 0);
    if (!$id || !$sid) exit('missing');

    // Conta votos EXCLUINDO o presidente
    $row = $pdo->prepare("
        SELECT
          SUM(v.voto='favor')     AS f,
          SUM(v.voto='contra')    AS c,
          SUM(v.voto='abstencao') AS a
        FROM votos v
        JOIN usuarios u ON u.id = v.vereador_id AND COALESCE(u.eh_presidente,0)=0
        WHERE v.sessao_materia_id=:id
    ");
    $row->execute([':id' => $id]);
    $r = $row->fetch() ?: ['f' => 0, 'c' => 0, 'a' => 0];

    $resultado = ((int)$r['f'] >= (int)$r['c']) ? 'aprovada' : 'rejeitada';

    $pdo->prepare("UPDATE sessao_materias
                   SET status='finalizada',
                       resultado=:res,
                       votos_favor=:f, votos_contra=:c, votos_abstencao=:a
                   WHERE id=:id AND sessao_id=:s")
      ->execute([
        ':res' => $resultado,
        ':f' => $r['f'] ?? 0,
        ':c' => $r['c'] ?? 0,
        ':a' => $r['a'] ?? 0,
        ':id' => $id,
        ':s' => $sid
      ]);

    header('Location:/arapiraca/admin_materia_nova.php?sessao=' . $sid);
    exit;

    /* ======== Matérias: ativar/inativar, publicar e editar ======== */

  case 'materia_marcar_inativa': {
      require_operador();
      $sm_id     = (int)($_GET['id'] ?? 0);       // id de sessao_materias
      $sessao_id = (int)($_GET['sessao_id'] ?? 0);
      if (!$sm_id || !$sessao_id) exit('missing');

      $st = $pdo->prepare("SELECT sessao_id, status FROM sessao_materias WHERE id=:id");
      $st->execute([':id' => $sm_id]);
      $sm = $st->fetch();

      if (!$sm || (int)$sm['sessao_id'] !== $sessao_id) {
        header("Location:/arapiraca/admin_materia_nova.php?sessao={$sessao_id}&err=" . urlencode('Matéria não encontrada.'));
        exit;
      }
      if (in_array($sm['status'], ['votacao_aberta', 'finalizada'], true)) {
        header("Location:/arapiraca/admin_materia_nova.php?sessao={$sessao_id}&err=" . urlencode('Não é possível inativar matéria em votação ou finalizada.'));
        exit;
      }

      $pdo->prepare("UPDATE sessao_materias SET status='inativa' WHERE id=:id")->execute([':id' => $sm_id]);
      header("Location:/arapiraca/admin_materia_nova.php?sessao={$sessao_id}&msg=" . urlencode('Matéria marcada como inativa.'));
      exit;
    }

  case 'materia_marcar_ativa': {
      require_operador();
      $sm_id     = (int)($_GET['id'] ?? 0);
      $sessao_id = (int)($_GET['sessao_id'] ?? 0);
      if (!$sm_id || !$sessao_id) exit('missing');

      $st = $pdo->prepare("SELECT sessao_id, status FROM sessao_materias WHERE id=:id");
      $st->execute([':id' => $sm_id]);
      $sm = $st->fetch();

      if (!$sm || (int)$sm['sessao_id'] !== $sessao_id) {
        header("Location:/arapiraca/admin_materia_nova.php?sessao={$sessao_id}&err=" . urlencode('Matéria não encontrada.'));
        exit;
      }
      if (in_array($sm['status'], ['votacao_aberta', 'finalizada'], true)) {
        header("Location:/arapiraca/admin_materia_nova.php?sessao={$sessao_id}&err=" . urlencode('Não é possível reativar enquanto estiver em votação ou finalizada.'));
        exit;
      }

      $pdo->prepare("UPDATE sessao_materias SET status='aguardando' WHERE id=:id")->execute([':id' => $sm_id]);
      header("Location:/arapiraca/admin_materia_nova.php?sessao={$sessao_id}&msg=" . urlencode('Matéria reativada.'));
      exit;
    }

  case 'sm_toggle_publicar': {
      require_operador();
      $sm_id     = (int)($_GET['id'] ?? 0);       // id de sessao_materias
      $to        = (int)($_GET['to'] ?? 1) ? 1 : 0;
      $sessao_id = (int)($_GET['sessao_id'] ?? 0);
      if (!$sm_id || !$sessao_id) exit('missing');

      $st = $pdo->prepare("SELECT sessao_id, status FROM sessao_materias WHERE id=:id");
      $st->execute([':id' => $sm_id]);
      $sm = $st->fetch();

      if (!$sm || (int)$sm['sessao_id'] !== $sessao_id) {
        header("Location:/arapiraca/admin_materia_nova.php?sessao={$sessao_id}&err=" . urlencode('Matéria não encontrada.'));
        exit;
      }
      if ($sm['status'] !== 'finalizada') {
        header("Location:/arapiraca/admin_materia_nova.php?sessao={$sessao_id}&err=" . urlencode('Só é possível alterar a publicação após finalização.'));
        exit;
      }

      $pdo->prepare("UPDATE sessao_materias SET publicar_site=:pub WHERE id=:id")
        ->execute([':pub' => $to, ':id' => $sm_id]);

      $msg = $to ? 'Marcada para publicar no site.' : 'Marcada para NÃO publicar no site.';
      header("Location:/arapiraca/admin_materia_nova.php?sessao={$sessao_id}&msg=" . urlencode($msg));
      exit;
    }

  case 'materia_editar': {
      require_operador();

      $materia_id = (int)($_POST['materia_id'] ?? 0);
      $sm_id      = (int)($_POST['sm_id'] ?? 0);
      $sessao_id  = (int)($_GET['sessao_id'] ?? $_POST['sessao_id'] ?? 0);
      if (!$materia_id || !$sm_id || !$sessao_id) exit('missing');

      $titulo   = trim($_POST['titulo'] ?? '');
      $tipo     = trim($_POST['tipo'] ?? 'Projeto de Lei');
      $numero   = trim($_POST['numero'] ?? '');
      $ano      = (int)($_POST['ano'] ?? date('Y'));
      $autor_id = (int)($_POST['autor_id'] ?? 0);
      $descr    = trim($_POST['descricao'] ?? '');

      $st = $pdo->prepare("SELECT sessao_id, status FROM sessao_materias WHERE id=:id AND materia_id=:m");
      $st->execute([':id' => $sm_id, ':m' => $materia_id]);
      $sm = $st->fetch();
      if (!$sm || (int)$sm['sessao_id'] !== $sessao_id) {
        header("Location:/arapiraca/admin_materia_nova.php?sessao={$sessao_id}&err=" . urlencode('Matéria não encontrada.'));
        exit;
      }
      if ($sm['status'] === 'votacao_aberta') {
        header("Location:/arapiraca/admin_materia_nova.php?sessao={$sessao_id}&err=" . urlencode('Feche a votação antes de editar.'));
        exit;
      }

      if ($titulo === '' || $autor_id <= 0) {
        header("Location:/arapiraca/admin_materia_nova.php?sessao={$sessao_id}&err=" . urlencode('Preencha título e propositor.'));
        exit;
      }
      $chk = $pdo->prepare("SELECT COUNT(*) FROM usuarios WHERE id=:id AND tipo_usuario IN ('vereador','proponente') AND ativo=1");
      $chk->execute([':id' => $autor_id]);
      if (!$chk->fetchColumn()) {
        header("Location:/arapiraca/admin_materia_nova.php?sessao={$sessao_id}&err=" . urlencode('Propositor inválido.'));
        exit;
      }

      $pdo->prepare("
        UPDATE materias
           SET numero=:n, ano=:a, tipo=:t, titulo=:ti, descricao=:d, autor_id=:au
         WHERE id=:id
    ")->execute([
        ':n' => $numero,
        ':a' => $ano,
        ':t' => $tipo,
        ':ti' => $titulo,
        ':d' => $descr,
        ':au' => $autor_id,
        ':id' => $materia_id
      ]);

      header("Location:/arapiraca/admin_materia_nova.php?sessao={$sessao_id}&msg=" . urlencode('Matéria atualizada.'));
      exit;
    }

    /* -------- Ações do vereador -------- */
  case 'confirmar_presenca':
    $sid = (int)($_GET['sessao_id'] ?? 0);
    if (!$sid || empty($_SESSION['user_id'])) exit('missing');

    $chk = $pdo->prepare("SELECT presente FROM quorum WHERE sessao_id=:s AND vereador_id=:v");
    $chk->execute([':s' => $sid, ':v' => $_SESSION['user_id']]);
    if ((int)$chk->fetchColumn() === 1) {
      header('Location:/arapiraca/vereador.php?sessao=' . $sid);
      exit;
    }

    $pdo->prepare("INSERT INTO quorum (sessao_id, vereador_id, presente)
                   VALUES (:s,:v,1)
                   ON DUPLICATE KEY UPDATE presente=1, updated_at=CURRENT_TIMESTAMP")
      ->execute([':s' => $sid, ':v' => $_SESSION['user_id']]);

    header('Location:/arapiraca/vereador.php?sessao=' . $sid);
    exit;

  case 'votar':
    if (empty($_SESSION['user_id'])) {
      http_response_code(401);
      exit('unauth');
    }
    if (($_SESSION['tipo'] ?? '') !== 'vereador') {
      http_response_code(403);
      exit('forbidden');
    }

    $id = (int)($_GET['id'] ?? 0);         // id de sessao_materias
    $v  = $_GET['v'] ?? '';
    if (!$id || !in_array($v, ['favor', 'contra', 'abstencao'], true)) exit('dados inválidos');

    // Presidente não vota
    $qPres = $pdo->prepare("SELECT COALESCE(eh_presidente,0) FROM usuarios WHERE id=:id");
    $qPres->execute([':id' => $_SESSION['user_id']]);
    if ((int)$qPres->fetchColumn() === 1) {
      $sidQ = $pdo->prepare("SELECT sessao_id FROM sessao_materias WHERE id=:id");
      $sidQ->execute([':id' => $id]);
      $sidBack = (int)$sidQ->fetchColumn();
      header('Location:/arapiraca/vereador.php?sessao=' . $sidBack . '&msg=presidente_nao_vota');
      exit;
    }

    // Sessão e status da matéria
    $smQ = $pdo->prepare("SELECT sessao_id, status FROM sessao_materias WHERE id=:id");
    $smQ->execute([':id' => $id]);
    $smRow = $smQ->fetch();
    $sid = (int)($smRow['sessao_id'] ?? 0);
    $smStatus = $smRow['status'] ?? '';
    if (!$sid) exit('matéria inválida');

    // Confirma presença
    $ok = $pdo->prepare("SELECT presente FROM quorum WHERE sessao_id=:s AND vereador_id=:v");
    $ok->execute([':s' => $sid, ':v' => $_SESSION['user_id']]);
    if (!($ok->fetchColumn())) exit('confirme presença');

    // Busca voto existente
    $ja = $pdo->prepare("SELECT voto FROM votos WHERE sessao_materia_id=:m AND vereador_id=:v");
    $ja->execute([':m' => $id, ':v' => $_SESSION['user_id']]);
    $votoExistente = $ja->fetchColumn();

    // Só permite inserir/alterar enquanto a matéria estiver com votação aberta
    if ($votoExistente !== false && $votoExistente !== null) {
      if ($smStatus === 'votacao_aberta') {
        $pdo->prepare("
                UPDATE votos
                   SET voto = :vt, updated_at = CURRENT_TIMESTAMP
                 WHERE sessao_materia_id = :m AND vereador_id = :v
            ")->execute([':vt' => $v, ':m' => $id, ':v' => $_SESSION['user_id']]);
      } else {
        header('Location:/arapiraca/vereador.php?sessao=' . $sid . '&msg=votacao_encerrada_sem_alteracao');
        exit;
      }
    } else {
      if ($smStatus !== 'votacao_aberta') {
        header('Location:/arapiraca/vereador.php?sessao=' . $sid . '&msg=votacao_nao_aberta');
        exit;
      }
      $ip = $_SERVER['REMOTE_ADDR'] ?? null;
      $pdo->prepare("INSERT INTO votos (sessao_materia_id, vereador_id, voto, is_secreto, ip_address)
                       VALUES (:m,:v,:vt,0,:ip)")
        ->execute([':m' => $id, ':v' => $_SESSION['user_id'], ':vt' => $v, ':ip' => $ip]);
    }

    header('Location:/arapiraca/vereador.php?sessao=' . $sid);
    exit;

    /* -------- Pedidos de fala (vereador) -------- */
  case 'pedir_fala':
    if (empty($_SESSION['user_id'])) {
      http_response_code(401);
      exit('unauth');
    }
    if (($_SESSION['tipo'] ?? '') !== 'vereador') {
      http_response_code(403);
      exit('forbidden');
    }
    if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
      http_response_code(405);
      exit('method not allowed');
    }

    $sid   = (int)($_POST['sessao_id'] ?? 0);
    $tempo = max(1, min(30, (int)($_POST['tempo'] ?? 5)));
    if (!$sid) exit('missing');

    $q = $pdo->prepare("SELECT id FROM pedidos_fala
                        WHERE sessao_id=:s AND vereador_id=:v AND status IN ('pendente','autorizada')
                        ORDER BY id DESC LIMIT 1");
    $q->execute([':s' => $sid, ':v' => $_SESSION['user_id']]);
    if ($q->fetchColumn()) {
      header('Location:/arapiraca/vereador.php?sessao=' . $sid);
      exit;
    }

    $pdo->prepare("INSERT INTO pedidos_fala (sessao_id, vereador_id, status, tempo_solicitado)
                   VALUES (:s,:v,'pendente',:t)")
      ->execute([':s' => $sid, ':v' => $_SESSION['user_id'], ':t' => $tempo]);

    header('Location:/arapiraca/vereador.php?sessao=' . $sid);
    exit;

  case 'cancelar_pedido_fala':
    if (empty($_SESSION['user_id'])) {
      http_response_code(401);
      exit('unauth');
    }
    if (($_SESSION['tipo'] ?? '') !== 'vereador') {
      http_response_code(403);
      exit('forbidden');
    }

    $sid = (int)($_GET['sessao_id'] ?? 0);
    if (!$sid) exit('missing');

    $pdo->prepare("UPDATE pedidos_fala
                      SET status='cancelada', updated_at=CURRENT_TIMESTAMP
                    WHERE sessao_id=:s AND vereador_id=:v AND status='pendente'
                    ORDER BY id DESC LIMIT 1")
      ->execute([':s' => $sid, ':v' => $_SESSION['user_id']]);

    header('Location:/arapiraca/vereador.php?sessao=' . $sid);
    exit;

    /* -------- Pedidos de fala (OPERADOR) -------- */
  case 'autorizar_fala':
    require_operador();
    $pedido_id = (int)($_POST['id'] ?? $_GET['id'] ?? 0);
    $min = isset($_POST['min']) ? (int)$_POST['min'] : (isset($_GET['min']) ? (int)$_GET['min'] : 0);
    if ($min) {
      $min = max(1, min(60, $min));
    }
    if (!$pedido_id) exit('missing');

    $p = $pdo->prepare("SELECT sessao_id FROM pedidos_fala WHERE id=:id");
    $p->execute([':id' => $pedido_id]);
    $sid = (int)$p->fetchColumn();
    if (!$sid) exit('pedido inválido');

    $pdo->prepare("UPDATE pedidos_fala
                      SET status='finalizada', tempo_fim=NOW(), updated_at=NOW()
                    WHERE sessao_id=:s AND status='autorizada'")
      ->execute([':s' => $sid]);

    if ($min > 0) {
      $pdo->prepare("UPDATE pedidos_fala
                        SET status='autorizada', tempo_inicio=NOW(), tempo_fim=NULL, tempo_solicitado=:t, updated_at=NOW()
                      WHERE id=:id")
        ->execute([':id' => $pedido_id, ':t' => $min]);
    } else {
      $pdo->prepare("UPDATE pedidos_fala
                        SET status='autorizada', tempo_inicio=NOW(), tempo_fim=NULL, updated_at=NOW()
                      WHERE id=:id")
        ->execute([':id' => $pedido_id]);
    }

    header('Location:/arapiraca/admin_materia_nova.php?sessao=' . $sid);
    exit;

  case 'encerrar_fala':
  case 'finalizar_fala':
    require_operador();
    $sid = (int)($_GET['sessao_id'] ?? 0);
    if (!$sid) {
      $sid = (int)$pdo->query("SELECT sessao_id FROM pedidos_fala WHERE status='autorizada' ORDER BY id DESC LIMIT 1")->fetchColumn();
      if (!$sid) exit('missing');
    }

    $pdo->prepare("UPDATE pedidos_fala
                      SET status='finalizada', tempo_fim=NOW(), updated_at=NOW()
                    WHERE sessao_id=:s AND status='autorizada'")
      ->execute([':s' => $sid]);

    header('Location:/arapiraca/admin_materia_nova.php?sessao=' . $sid);
    exit;

  case 'cancelar_fala':
    require_operador();
    $pedido_id = (int)($_GET['id'] ?? 0);
    $sid = (int)($_GET['sessao_id'] ?? 0);
    if (!$pedido_id || !$sid) exit('missing');

    $pdo->prepare("UPDATE pedidos_fala
                      SET status='cancelada', updated_at=NOW()
                    WHERE id=:id AND sessao_id=:s AND status IN('pendente','autorizada')")
      ->execute([':id' => $pedido_id, ':s' => $sid]);

    header('Location:/arapiraca/admin_materia_nova.php?sessao=' . $sid);
    exit;

    /* -------- PRORROGAR FALA (+N minutos, teto 60) -------- */
  case 'prorrogar_fala':
    require_operador();
    $sid   = (int)($_GET['sessao_id'] ?? 0);
    $delta = (int)($_GET['delta'] ?? 1);
    if (!$sid) exit('missing');

    if ($delta < 1)  $delta = 1;
    if ($delta > 15) $delta = 15;

    $pdo->prepare("
        UPDATE pedidos_fala
           SET tempo_solicitado = LEAST(60, tempo_solicitado + :d),
               updated_at = NOW()
         WHERE sessao_id = :s AND status = 'autorizada'
         ORDER BY id DESC
         LIMIT 1
    ")->execute([':d' => $delta, ':s' => $sid]);

    header('Location:/arapiraca/admin_materia_nova.php?sessao=' . $sid);
    exit;

    /* ===== Operador: marcar presença por vereador ===== */
  case 'op_quorum_set':
    require_operador();
    $sessao_id   = (int)($_GET['sessao_id'] ?? 0);
    $vereador_id = (int)($_GET['vereador_id'] ?? 0);
    $presente    = (int)($_GET['presente'] ?? 1) ? 1 : 0;
    if ($sessao_id <= 0 || $vereador_id <= 0) {
      json_out(['ok' => false, 'msg' => 'Dados inválidos']);
    }

    $pdo->prepare("
    INSERT INTO quorum (sessao_id, vereador_id, presente)
    VALUES (:s,:v,:p)
    ON DUPLICATE KEY UPDATE presente=:p, updated_at=CURRENT_TIMESTAMP
  ")->execute([':s' => $sessao_id, ':v' => $vereador_id, ':p' => $presente]);

    json_out(['ok' => true]);
    break;

  /* ===== Operador: pedir voz por vereador ===== */
  case 'op_pedir_fala_por':
    require_operador();
    $sessao_id   = (int)($_GET['sessao_id'] ?? 0);
    $vereador_id = (int)($_GET['vereador_id'] ?? 0);
    $min         = max(1, min(60, (int)($_GET['min'] ?? 5)));
    if ($sessao_id <= 0 || $vereador_id <= 0) {
      json_out(['ok' => false, 'msg' => 'Dados inválidos']);
    }

    // evita duplicidade (pendente ou já autorizada)
    $q = $pdo->prepare("
      SELECT COUNT(*) FROM pedidos_fala
       WHERE sessao_id=:s AND vereador_id=:v
         AND status IN ('pendente','autorizada')
  ");
    $q->execute([':s' => $sessao_id, ':v' => $vereador_id]);
    if ($q->fetchColumn() > 0) {
      json_out(['ok' => true, 'msg' => 'Já possui pedido pendente/andamento.']);
    }

    $pdo->prepare("
    INSERT INTO pedidos_fala (sessao_id, vereador_id, status, tempo_solicitado)
    VALUES (:s,:v,'pendente',:t)
  ")->execute([':s' => $sessao_id, ':v' => $vereador_id, ':t' => $min]);

    json_out(['ok' => true]);
    break;

  /* ===== Operador: APARTE (pausa fala atual e abre 2min para outro vereador) ===== */
  case 'op_aparte_toggle':
    require_operador();
    $sessao_id   = (int)($_GET['sessao_id'] ?? 0);
    $vereador_id = (int)($_GET['vereador_id'] ?? 0);

    if ($sessao_id <= 0 || $vereador_id <= 0) {
      json_out(['ok' => false, 'msg' => 'Dados inválidos']);
    }

    // Se já existe aparte ativo nesta sessão, clicar de novo encerra o aparte
    $ap = aparte_get($sessao_id);
    if ($ap && $ap['aparte_id'] > 0) {

      // Finaliza o pedido de fala do aparte
      $pdo->prepare("
          UPDATE pedidos_fala
             SET status='finalizada', tempo_fim=NOW(), updated_at=NOW()
           WHERE id=:id AND sessao_id=:s
      ")->execute([':id' => $ap['aparte_id'], ':s' => $sessao_id]);

      // Ajusta o tempo_inicio da fala principal para "descontar" o tempo do aparte
      $nowEpoch = (int)$pdo->query("SELECT UNIX_TIMESTAMP(NOW())")->fetchColumn();
      $st = $pdo->prepare("
        SELECT UNIX_TIMESTAMP(tempo_inicio) AS ts
          FROM pedidos_fala
         WHERE id=:id AND sessao_id=:s
         LIMIT 1
      ");
      $st->execute([':id' => $ap['principal_id'], ':s' => $sessao_id]);
      $ts = (int)$st->fetchColumn();

      if ($ts > 0) {
        $aparteDur = max(0, $nowEpoch - (int)$ap['aparte_started_at']); // segundos de aparte
        $novoStart = $ts + $aparteDur;
        $pdo->prepare("UPDATE pedidos_fala SET tempo_inicio = FROM_UNIXTIME(:ts) WHERE id=:id")
          ->execute([':ts' => $novoStart, ':id' => $ap['principal_id']]);
      }

      aparte_clear($sessao_id);
      json_out(['ok' => true, 'modo' => 'aparte_encerrado']);
    }

    // Não havia aparte ativo: inicia um novo, se existir fala principal autorizada
    $q = $pdo->prepare("
      SELECT pf.id,
             pf.tempo_solicitado,
             UNIX_TIMESTAMP(pf.tempo_inicio) AS started_at
        FROM pedidos_fala pf
       WHERE pf.sessao_id = :s
         AND pf.status    = 'autorizada'
       ORDER BY pf.id DESC
       LIMIT 1
    ");
    $q->execute([':s' => $sessao_id]);
    $principal = $q->fetch();

    if (!$principal) {
      json_out(['ok' => false, 'msg' => 'Não há fala principal em andamento.']);
    }

    $nowEpoch = (int)$pdo->query("SELECT UNIX_TIMESTAMP(NOW())")->fetchColumn();
    $totalSeg = ((int)$principal['tempo_solicitado']) * 60;
    $elapsed  = max(0, $nowEpoch - (int)$principal['started_at']);
    $restante = max(0, $totalSeg - $elapsed); // segundos restantes da fala principal

    // Cria o pedido de fala do aparte já como autorizado, com 2 minutos
    $minAparte = 2;
    $stIns = $pdo->prepare("
      INSERT INTO pedidos_fala (sessao_id, vereador_id, status, tempo_solicitado, tempo_inicio)
      VALUES (:s, :v, 'autorizada', :t, NOW())
    ");
    $stIns->execute([':s' => $sessao_id, ':v' => $vereador_id, ':t' => $minAparte]);
    $aparteId = (int)$pdo->lastInsertId();

    // Salva estado runtime do aparte (para o painel saber o tempo pausado)
    aparte_set($sessao_id, (int)$principal['id'], $restante, $aparteId, $vereador_id);

    json_out(['ok' => true, 'modo' => 'aparte_iniciado']);
    break;

  /* ===== Operador: votar por vereador ===== */
  case 'op_votar_por':
    require_operador();
    $sm_id       = (int)($_GET['sm_id'] ?? 0);
    $vereador_id = (int)($_GET['vereador_id'] ?? 0);
    $v           = $_GET['v'] ?? '';
    if ($sm_id <= 0 || $vereador_id <= 0 || !in_array($v, ['favor', 'contra', 'abstencao'], true)) {
      json_out(['ok' => false, 'msg' => 'Dados inválidos']);
    }

    // checa status da matéria
    $qr = $pdo->prepare("SELECT sessao_id, status FROM sessao_materias WHERE id=:id");
    $qr->execute([':id' => $sm_id]);
    $row = $qr->fetch();
    if (!$row || $row['status'] !== 'votacao_aberta') {
      json_out(['ok' => false, 'msg' => 'Votação não está aberta.']);
    }
    $sessao_id = (int)$row['sessao_id'];

    // exige presença marcada
    $ok = $pdo->prepare("SELECT presente FROM quorum WHERE sessao_id=:s AND vereador_id=:v");
    $ok->execute([':s' => $sessao_id, ':v' => $vereador_id]);
    if ((int)$ok->fetchColumn() !== 1) {
      json_out(['ok' => false, 'msg' => 'Marque presença antes.']);
    }

    // não permite votar presidente
    $qp = $pdo->prepare("SELECT COALESCE(eh_presidente,0) FROM usuarios WHERE id=:id");
    $qp->execute([':id' => $vereador_id]);
    if ((int)$qp->fetchColumn() === 1) {
      json_out(['ok' => false, 'msg' => 'Presidente não vota.']);
    }

    // insere/atualiza voto
    $ja = $pdo->prepare("SELECT id FROM votos WHERE sessao_materia_id=:m AND vereador_id=:v LIMIT 1");
    $ja->execute([':m' => $sm_id, ':v' => $vereador_id]);
    $exists = (int)($ja->fetchColumn() ?: 0);

    if ($exists) {
      $pdo->prepare("UPDATE votos SET voto=:vt, updated_at=CURRENT_TIMESTAMP WHERE id=:id")
        ->execute([':vt' => $v, ':id' => $exists]);
    } else {
      $ip = $_SERVER['REMOTE_ADDR'] ?? null;
      $pdo->prepare("INSERT INTO votos (sessao_materia_id, vereador_id, voto, is_secreto, ip_address)
                   VALUES (:m,:v,:vt,0,:ip)")
        ->execute([':m' => $sm_id, ':v' => $vereador_id, ':vt' => $v, ':ip' => $ip]);
    }

    json_out(['ok' => true]);
    break;


  /* ---------------- CRUD de USUÁRIO ---------------- */
  case 'usuario_salvar':
    require_operador();
    if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
      http_response_code(405);
      exit('method not allowed');
    }

    $id      = (int)($_POST['id'] ?? 0);
    $nome    = trim($_POST['nome'] ?? '');
    $email   = strtolower(trim($_POST['email'] ?? ''));
    $tipo    = $_POST['tipo_usuario'] ?? 'vereador';
    $partido = trim($_POST['partido'] ?? '');
    $ativo   = (int)($_POST['ativo'] ?? 1);
    $senha   = trim($_POST['senha'] ?? '');
    $eh_presidente = (int)($_POST['eh_presidente'] ?? 0);

    if (!$nome || !$email || !in_array($tipo, ['operador', 'vereador'], true)) {
      header('Location:/arapiraca/admin_usuario_form.php?id=' . $id . '&msg=Dados+inválidos');
      exit;
    }

    try {
      if ($eh_presidente === 1 && $tipo === 'vereador') {
        if ($id) {
          $pdo->prepare("UPDATE usuarios SET eh_presidente=0 WHERE tipo_usuario='vereador' AND id<>:id")->execute([':id' => $id]);
        } else {
          $pdo->exec("UPDATE usuarios SET eh_presidente=0 WHERE tipo_usuario='vereador'");
        }
      }

      if ($id) {
        $cur = $pdo->prepare("SELECT foto FROM usuarios WHERE id=:id");
        $cur->execute([':id' => $id]);
        $oldFoto = $cur->fetchColumn();
        $foto = $oldFoto;

        if (!empty($_FILES['foto']) && $_FILES['foto']['error'] !== UPLOAD_ERR_NO_FILE) {
          $foto = save_user_photo($_FILES['foto'], $oldFoto);
        }

        $sql = "UPDATE usuarios SET
                      nome=:n, email=:e, tipo_usuario=:t, partido=:p, ativo=:a, foto=:f, eh_presidente=:pres";
        $params = [':n' => $nome, ':e' => $email, ':t' => $tipo, ':p' => $partido, ':a' => $ativo, ':f' => $foto, ':pres' => $eh_presidente, ':id' => $id];

        if ($senha !== '') {
          $sql .= ", senha_hash=:h";
          $params[':h'] = password_hash($senha, PASSWORD_BCRYPT, ['cost' => 10]);
        }
        $sql .= " WHERE id=:id";

        $pdo->prepare($sql)->execute($params);
        header('Location:/arapiraca/admin_usuario_form.php?id=' . $id . '&msg=Salvo');
        exit;
      } else {
        $hash = $senha !== ''
          ? password_hash($senha, PASSWORD_BCRYPT, ['cost' => 10])
          : password_hash('123456', PASSWORD_BCRYPT, ['cost' => 10]);

        $foto = null;
        if (!empty($_FILES['foto']) && $_FILES['foto']['error'] !== UPLOAD_ERR_NO_FILE) {
          $foto = save_user_photo($_FILES['foto'], null);
        }

        $pdo->prepare("INSERT INTO usuarios (nome, email, senha_hash, tipo_usuario, partido, ativo, foto, eh_presidente)
                           VALUES (:n,:e,:h,:t,:p,:a,:f,:pres)")
          ->execute([':n' => $nome, ':e' => $email, ':h' => $hash, ':t' => $tipo, ':p' => $partido, ':a' => $ativo, ':f' => $foto, ':pres' => $eh_presidente]);

        header('Location:/arapiraca/admin_usuarios.php?msg=Usuário+criado');
        exit;
      }
    } catch (Throwable $ex) {
      $m = urlencode('Erro: ' . $ex->getMessage());
      header('Location:/arapiraca/admin_usuario_form.php?id=' . $id . '&msg=' . $m);
      exit;
    }

  case 'usuario_toggle':
    require_operador();
    $id = (int)($_GET['id'] ?? 0);
    $to = (int)($_GET['to'] ?? 0);
    if (!$id) {
      header('Location:/arapiraca/admin_usuarios.php?msg=ID+inválido');
      exit;
    }
    $pdo->prepare("UPDATE usuarios SET ativo=:a WHERE id=:id")->execute([':a' => $to, ':id' => $id]);
    header('Location:/arapiraca/admin_usuarios.php?msg=' . ($to ? 'Ativado' : 'Desativado'));
    exit;

    /* ==================== LEGISLATURAS ==================== */

  case 'leg_salvar':
    require_operador();
    if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
      http_response_code(405);
      exit('method not allowed');
    }

    $id          = (int)($_POST['id'] ?? 0);
    $numero      = (int)($_POST['numero'] ?? 0);
    $periodo     = trim($_POST['periodo'] ?? '');
    $data_inicio = trim($_POST['data_inicio'] ?? '');
    $data_fim    = trim($_POST['data_fim'] ?? '');

    if ($numero <= 0 || !$data_inicio || !$data_fim) {
      header('Location:/arapiraca/admin_legislatura.php?msg=' . urlencode('Preencha número, início e fim.'));
      exit;
    }

    try {
      if ($id) {
        $pdo->prepare("
          UPDATE legislaturas
             SET numero=:n, periodo=:p, data_inicio=:di, data_fim=:df
           WHERE id=:id
        ")->execute([':n' => $numero, ':p' => $periodo, ':di' => $data_inicio, ':df' => $data_fim, ':id' => $id]);

        header('Location:/arapiraca/admin_legislatura.php?reopen=' . $id . '&tab=dados&msg=' . urlencode('Salvo'));
        exit;
      } else {
        $st = $pdo->prepare("
          INSERT INTO legislaturas (numero, periodo, data_inicio, data_fim, ativo)
          VALUES (:n,:p,:di,:df,1)
        ");
        $st->execute([':n' => $numero, ':p' => $periodo, ':di' => $data_inicio, ':df' => $data_fim]);
        $newId = (int)$pdo->lastInsertId();

        header('Location:/arapiraca/admin_legislatura.php?reopen=' . $newId . '&tab=dados&msg=' . urlencode('Criada'));
        exit;
      }
    } catch (Throwable $e) {
      header('Location:/arapiraca/admin_legislatura.php?msg=' . urlencode('Erro ao salvar: ' . $e->getMessage()));
      exit;
    }

  case 'leg_toggle':
    require_operador();
    $id = (int)($_GET['id'] ?? 0);
    $to = (int)($_GET['to'] ?? 0) ? 1 : 0;
    if (!$id) {
      header('Location:/arapiraca/admin_legislatura.php?msg=ID+inválido');
      exit;
    }
    $pdo->prepare("UPDATE legislaturas SET ativo=:a WHERE id=:id")->execute([':a' => $to, ':id' => $id]);
    header('Location:/arapiraca/admin_legislatura.php?msg=' . urlencode($to ? 'Ativada' : 'Inativada'));
    exit;

  case 'leg_excluir':
    require_operador();
    $id = (int)($_GET['id'] ?? 0);
    if (!$id) {
      header('Location:/arapiraca/admin_legislatura.php?msg=ID+inválido');
      exit;
    }

    $pdo->prepare("DELETE FROM legislatura_mesa WHERE legislatura_id=:id")->execute([':id' => $id]);
    $pdo->prepare("DELETE FROM legislatura_vereadores WHERE legislatura_id=:id")->execute([':id' => $id]);
    $pdo->prepare("DELETE FROM legislaturas WHERE id=:id")->execute([':id' => $id]);

    header('Location:/arapiraca/admin_legislatura.php?msg=' . urlencode('Excluída'));
    exit;

  case 'leg_info':
    require_operador();
    $id = (int)($_GET['id'] ?? 0);
    if (!$id) json_out(['ok' => false, 'err' => 'missing id']);

    $s = $pdo->prepare("SELECT * FROM legislaturas WHERE id=:id LIMIT 1");
    $s->execute([':id' => $id]);
    $row = $s->fetch();
    if (!$row) json_out(['ok' => false, 'err' => 'not found']);

    $v = $pdo->prepare("
      SELECT lv.id, u.nome, COALESCE(u.partido,'') AS partido
      FROM legislatura_vereadores lv
      JOIN usuarios u ON u.id = lv.vereador_id
      WHERE lv.legislatura_id = :id
      ORDER BY u.nome
    ");
    $v->execute([':id' => $id]);
    $vereadores = $v->fetchAll();

    $m = $pdo->prepare("
      SELECT
        lm.id,
        u.nome,
        COALESCE(u.partido,'') AS partido,
        lm.cargo,
        COALESCE(lm.sessao_legislativa,'') AS sessao_legislativa
      FROM legislatura_mesa lm
      JOIN usuarios u ON u.id = lm.vereador_id
      WHERE lm.legislatura_id = :id
      ORDER BY FIELD(lm.cargo,'Presidente','Vice-Presidente','1º Secretário','2º Secretário','3º Secretário'), u.nome
    ");
    $m->execute([':id' => $id]);
    $mesa = $m->fetchAll();

    json_out(['ok' => true, 'row' => $row, 'vereadores' => $vereadores, 'mesa' => $mesa]);

  case 'leg_add_vereador':
    require_operador();
    $leg_id = (int)($_GET['leg_id'] ?? $_POST['leg_id'] ?? 0);
    $vereador_id = (int)($_GET['vereador_id'] ?? $_POST['vereador_id'] ?? 0);

    if ($leg_id <= 0) {
      header('Location:/arapiraca/admin_legislatura.php?msg=' . urlencode('Salve a legislatura antes de vincular vereadores.'));
      exit;
    }
    if ($vereador_id <= 0) {
      header("Location:/arapiraca/admin_legislatura.php?reopen=$leg_id&tab=veread&msg=" . urlencode('Vereador inválido'));
      exit;
    }

    $ok = $pdo->prepare("SELECT COUNT(*) FROM usuarios WHERE id=:id AND tipo_usuario='vereador' AND ativo=1");
    $ok->execute([':id' => $vereador_id]);
    if (!$ok->fetchColumn()) {
      header("Location:/arapiraca/admin_legislatura.php?reopen=$leg_id&tab=veread&msg=" . urlencode('Vereador inativo/ inválido'));
      exit;
    }

    $pdo->prepare("
      INSERT INTO legislatura_vereadores (legislatura_id, vereador_id)
      SELECT :l, :v FROM DUAL
      WHERE NOT EXISTS (
        SELECT 1 FROM legislatura_vereadores WHERE legislatura_id=:l AND vereador_id=:v
      )
    ")->execute([':l' => $leg_id, ':v' => $vereador_id]);

    header("Location:/arapiraca/admin_legislatura.php?reopen=$leg_id&tab=veread&msg=Adicionado");
    exit;

  case 'leg_del_vereador':
    require_operador();
    $id = (int)($_GET['id'] ?? 0);
    $leg_id = (int)($_GET['leg_id'] ?? 0);
    if ($id) {
      $pdo->prepare("DELETE FROM legislatura_vereadores WHERE id=:id")->execute([':id' => $id]);
    }
    header("Location:/arapiraca/admin_legislatura.php?reopen=$leg_id&tab=veread&msg=Removido");
    exit;

  case 'leg_add_mesa':
    require_operador();
    $leg_id      = (int)($_GET['leg_id']      ?? $_POST['leg_id']      ?? 0);
    $vereador_id = (int)($_GET['vereador_id'] ?? $_POST['vereador_id'] ?? 0);
    $cargo       = trim($_GET['cargo']        ?? $_POST['cargo']        ?? '');
    $sessao_leg  = trim($_GET['sessao_legislativa'] ?? $_POST['sessao_legislativa'] ?? '');
    if ($sessao_leg === '') {
      $sessao_leg = null;
    }

    if ($leg_id <= 0) {
      header('Location:/arapiraca/admin_legislatura.php?msg=' . urlencode('Salve a legislatura antes de montar a mesa.'));
      exit;
    }
    if ($vereador_id <= 0 || $cargo === '') {
      header("Location:/arapiraca/admin_legislatura.php?reopen=$leg_id&tab=mesa&msg=" . urlencode('Dados inválidos'));
      exit;
    }

    $pdo->prepare("DELETE FROM legislatura_mesa WHERE legislatura_id=:l AND cargo=:c")
      ->execute([':l' => $leg_id, ':c' => $cargo]);

    $pdo->prepare("
        INSERT INTO legislatura_mesa (legislatura_id, vereador_id, cargo, sessao_legislativa)
        VALUES (:l, :v, :c, :s)
    ")->execute([':l' => $leg_id, ':v' => $vereador_id, ':c' => $cargo, ':s' => $sessao_leg]);

    header("Location:/arapiraca/admin_legislatura.php?reopen=$leg_id&tab=mesa&msg=Adicionado");
    exit;

  case 'leg_del_mesa':
    require_operador();
    $id = (int)($_GET['id'] ?? 0);
    $leg_id = (int)($_GET['leg_id'] ?? 0);
    if ($id) {
      $pdo->prepare("DELETE FROM legislatura_mesa WHERE id=:id")->execute([':id' => $id]);
    }
    header("Location:/arapiraca/admin_legislatura.php?reopen=$leg_id&tab=mesa&msg=Removido");
    exit;

    /* ==================== COMISSÕES ==================== */

  case 'com_salvar':
    require_operador();
    if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
      http_response_code(405);
      exit('method not allowed');
    }

    $id         = (int)($_POST['id'] ?? 0);
    $nome       = trim($_POST['nome'] ?? '');
    $tipo       = trim($_POST['tipo'] ?? '');
    $finalidade = trim($_POST['finalidade'] ?? '');

    if ($nome === '' || $tipo === '') {
      header('Location:/arapiraca/admin_comissao.php?msg=' . urlencode('Preencha nome e tipo.'));
      exit;
    }

    try {
      if ($id) {
        $pdo->prepare("UPDATE comissoes SET nome=:n, tipo=:t, finalidade=:f WHERE id=:id")
          ->execute([':n' => $nome, ':t' => $tipo, ':f' => $finalidade, ':id' => $id]);
        header('Location:/arapiraca/admin_comissao.php?reopen=' . $id . '&tab=dados&msg=' . urlencode('Salvo'));
      } else {
        $st = $pdo->prepare("INSERT INTO comissoes (nome,tipo,finalidade,ativo) VALUES (:n,:t,:f,1)");
        $st->execute([':n' => $nome, ':t' => $tipo, ':f' => $finalidade]);
        $newId = (int)$pdo->lastInsertId();
        header('Location:/arapiraca/admin_comissao.php?reopen=' . $newId . '&tab=dados&msg=' . urlencode('Criada'));
      }
    } catch (Throwable $e) {
      header('Location:/arapiraca/admin_comissao.php?msg=' . urlencode('Erro: ' . $e->getMessage()));
    }
    exit;

  case 'com_toggle':
    require_operador();
    $id = (int)($_GET['id'] ?? 0);
    $to = (int)($_GET['to'] ?? 0) ? 1 : 0;
    if (!$id) {
      header('Location:/arapiraca/admin_comissao.php?msg=ID+inválido');
      exit;
    }
    $pdo->prepare("UPDATE comissoes SET ativo=:a WHERE id=:id")->execute([':a' => $to, ':id' => $id]);
    header('Location:/arapiraca/admin_comissao.php?msg=' . urlencode($to ? 'Ativada' : 'Inativada'));
    exit;

  case 'com_excluir':
    require_operador();
    $id = (int)($_GET['id'] ?? 0);
    if (!$id) {
      header('Location:/arapiraca/admin_comissao.php?msg=ID+inválido');
      exit;
    }
    $pdo->prepare("DELETE FROM comissoes WHERE id=:id")->execute([':id' => $id]);
    header('Location:/arapiraca/admin_comissao.php?msg=' . urlencode('Excluída'));
    exit;

  case 'com_info':
    require_operador();
    $id = (int)($_GET['id'] ?? 0);
    if (!$id) json_out(['ok' => false, 'err' => 'missing id']);

    $s = $pdo->prepare("SELECT * FROM comissoes WHERE id=:id LIMIT 1");
    $s->execute([':id' => $id]);
    $row = $s->fetch();
    if (!$row) json_out(['ok' => false, 'err' => 'not found']);

    $m = $pdo->prepare("
      SELECT cm.id, u.nome, COALESCE(u.partido,'') AS partido, cm.cargo, cm.titular
      FROM comissao_membros cm
      JOIN usuarios u ON u.id = cm.vereador_id
      WHERE cm.comissao_id = :id
      ORDER BY FIELD(cm.cargo,'Presidente','Vice-Presidente','Relator','Membro','Suplente'), u.nome
    ");
    $m->execute([':id' => $id]);
    $membros = $m->fetchAll();

    json_out(['ok' => true, 'row' => $row, 'membros' => $membros]);

  case 'com_add_membro':
    require_operador();
    $comissao_id = (int)($_GET['comissao_id'] ?? $_POST['comissao_id'] ?? 0);
    $vereador_id = (int)($_GET['vereador_id'] ?? $_POST['vereador_id'] ?? 0);
    $cargo       = trim($_GET['cargo'] ?? $_POST['cargo'] ?? 'Membro');

    if ($comissao_id <= 0 || $vereador_id <= 0) {
      header('Location:/arapiraca/admin_comissao.php?msg=' . urlencode('Dados inválidos'));
      exit;
    }

    $ok = $pdo->prepare("SELECT COUNT(*) FROM usuarios WHERE id=:id AND tipo_usuario='vereador' AND ativo=1");
    $ok->execute([':id' => $vereador_id]);
    if (!$ok->fetchColumn()) {
      header("Location:/arapiraca/admin_comissao.php?reopen=$comissao_id&tab=comp&msg=" . urlencode('Vereador inválido'));
      exit;
    }

    if (in_array($cargo, ['Presidente', 'Relator', 'Vice-Presidente'], true)) {
      $pdo->prepare("DELETE FROM comissao_membros WHERE comissao_id=:c AND cargo=:cargo")
        ->execute([':c' => $comissao_id, ':cargo' => $cargo]);
    }

    $pdo->prepare("
      INSERT INTO comissao_membros (comissao_id, vereador_id, cargo, titular)
      SELECT :c, :v, :cargo, CASE WHEN :cargo='Suplente' THEN 0 ELSE 1 END FROM DUAL
      WHERE NOT EXISTS (
        SELECT 1 FROM comissao_membros WHERE comissao_id=:c AND vereador_id=:v
      )
    ")->execute([':c' => $comissao_id, ':v' => $vereador_id, ':cargo' => $cargo]);

    header("Location:/arapiraca/admin_comissao.php?reopen=$comissao_id&tab=comp&msg=Adicionado");
    exit;

  case 'com_del_membro':
    require_operador();
    $id = (int)($_GET['id'] ?? 0);
    $comissao_id = (int)($_GET['comissao_id'] ?? 0);
    if ($id) {
      $pdo->prepare("DELETE FROM comissao_membros WHERE id=:id")->execute([':id' => $id]);
    }
    header("Location:/arapiraca/admin_comissao.php?reopen=$comissao_id&tab=comp&msg=Removido");
    exit;

    /* ==================== LEGISLAÇÃO ==================== */

  case 'law_salvar':
    require_operador();
    if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
      http_response_code(405);
      exit('method not allowed');
    }

    $id          = (int)($_POST['id'] ?? 0);
    $data_norma  = trim($_POST['data_norma'] ?? '');
    $numero      = trim($_POST['numero'] ?? '');
    $tipo_id     = (int)($_POST['tipo_id'] ?? 0);
    $tema_id     = (int)($_POST['tema_id'] ?? 0) ?: null;
    $ementa      = trim($_POST['ementa'] ?? '');
    $palavras    = trim($_POST['palavras'] ?? '');

    if (!$data_norma || !$numero || $tipo_id <= 0) {
      header('Location:/arapiraca/admin_legislacao.php?msg=' . urlencode('Preencha data, número e tipo.'));
      exit;
    }

    try {
      if ($id) {
        $cur = $pdo->prepare("SELECT pdf_path FROM legislacao WHERE id=:id");
        $cur->execute([':id' => $id]);
        $oldPdf = $cur->fetchColumn();

        $pdf = $oldPdf;
        if (!empty($_FILES['pdf']) && $_FILES['pdf']['error'] !== UPLOAD_ERR_NO_FILE) {
          $pdf = save_law_pdf($_FILES['pdf'], $oldPdf);
        }

        $pdo->prepare("
          UPDATE legislacao
             SET data_norma=:d, numero=:n, tipo_id=:t, tema_id=:tm,
                 ementa=:e, palavras_chave=:p, pdf_path=:pdf
           WHERE id=:id
        ")->execute([
          ':d' => $data_norma,
          ':n' => $numero,
          ':t' => $tipo_id,
          ':tm' => $tema_id,
          ':e' => $ementa,
          ':p' => $palavras,
          ':pdf' => $pdf,
          ':id' => $id
        ]);

        header('Location:/arapiraca/admin_legislacao.php?reopen=' . $id . '&tab=dados&msg=' . urlencode('Salvo'));
        exit;
      } else {
        $pdf = null;
        if (!empty($_FILES['pdf']) && $_FILES['pdf']['error'] !== UPLOAD_ERR_NO_FILE) {
          $pdf = save_law_pdf($_FILES['pdf'], null);
        }

        $pdo->prepare("
          INSERT INTO legislacao (data_norma,numero,tipo_id,tema_id,ementa,palavras_chave,pdf_path)
          VALUES (:d,:n,:t,:tm,:e,:p,:pdf)
        ")->execute([
          ':d' => $data_norma,
          ':n' => $numero,
          ':t' => $tipo_id,
          ':tm' => $tema_id,
          ':e' => $ementa,
          ':p' => $palavras,
          ':pdf' => $pdf
        ]);

        header('Location:/arapiraca/admin_legislacao.php?msg=' . urlencode('Criada'));
        exit;
      }
    } catch (Throwable $e) {
      header('Location:/arapiraca/admin_legislacao.php?msg=' . urlencode('Erro: ' . $e->getMessage()));
      exit;
    }

  case 'law_excluir':
    require_operador();
    $id = (int)($_GET['id'] ?? 0);
    if (!$id) {
      header('Location:/arapiraca/admin_legislacao.php?msg=ID+inválido');
      exit;
    }

    $q = $pdo->prepare("SELECT pdf_path FROM legislacao WHERE id=:id");
    $q->execute([':id' => $id]);
    $pdf = $q->fetchColumn();
    if ($pdf) {
      $abs = __DIR__ . '/' . ltrim($pdf, '/\\');
      if (str_starts_with($abs, __DIR__ . '/uploads/leis') && file_exists($abs)) {
        @unlink($abs);
      }
    }

    $pdo->prepare("DELETE FROM legislacao WHERE id=:id")->execute([':id' => $id]);
    header('Location:/arapiraca/admin_legislacao.php?msg=' . urlencode('Excluída'));
    exit;

  case 'law_info':
    require_operador();
    $id = (int)($_GET['id'] ?? 0);
    if (!$id) json_out(['ok' => false, 'err' => 'missing id']);

    $s = $pdo->prepare("SELECT * FROM legislacao WHERE id=:id LIMIT 1");
    $s->execute([':id' => $id]);
    $row = $s->fetch();
    if (!$row) json_out(['ok' => false, 'err' => 'not found']);

    $r = $pdo->prepare("
      SELECT lr.id, lr.tipo_relacao, l.id AS norma_id, l.numero, l.data_norma
      FROM legislacao_relacoes lr
      JOIN legislacao l ON l.id = lr.relacionada_id
      WHERE lr.origem_id=:id
      ORDER BY l.data_norma DESC, l.id DESC
    ");
    $r->execute([':id' => $id]);
    $rels = [];
    foreach ($r as $x) {
      $rels[] = [
        'id' => (int)$x['id'],
        'tipo_relacao' => $x['tipo_relacao'],
        'norma_id' => (int)$x['norma_id'],
        'numero' => $x['numero'],
        'data_norma' => $x['data_norma'],
      ];
    }

    json_out(['ok' => true, 'row' => $row, 'rels' => $rels]);

  case 'law_search':
    require_operador();
    $q = trim($_GET['q'] ?? '');
    if ($q === '') json_out(['ok' => true, 'rows' => []]);

    $st = $pdo->prepare("
      SELECT l.id, l.numero, DATE_FORMAT(l.data_norma,'%d/%m/%Y') AS data,
             LEFT(l.ementa,80) AS ementa, t.nome AS tipo
      FROM legislacao l
      JOIN legislacao_tipos t ON t.id=l.tipo_id
      WHERE l.numero LIKE :q OR l.ementa LIKE :q OR l.palavras_chave LIKE :q
      ORDER BY l.data_norma DESC, l.id DESC LIMIT 20
    ");
    $st->execute([':q' => "%$q%"]);
    $rows = $st->fetchAll();
    json_out(['ok' => true, 'rows' => $rows]);

  case 'law_add_rel':
    require_operador();
    $origem = (int)($_GET['origem'] ?? 0);
    $rel    = (int)($_GET['rel'] ?? 0);
    $tipo   = $_GET['tipo'] ?? 'cita';
    if (!$origem || !$rel || $origem === $rel) {
      header('Location:/arapiraca/admin_legislacao.php?msg=Dados+inválidos');
      exit;
    }

    $pdo->prepare("
      INSERT IGNORE INTO legislacao_relacoes (origem_id,relacionada_id,tipo_relacao)
      VALUES (:o,:r,:t)
    ")->execute([':o' => $origem, ':r' => $rel, ':t' => $tipo]);

    header("Location:/arapiraca/admin_legislacao.php?reopen=$origem&tab=rel&msg=Relacionada+adicionada");
    exit;

  case 'law_del_rel':
    require_operador();
    $id = (int)($_GET['id'] ?? 0);
    $origem = (int)($_GET['origem'] ?? 0);
    if ($id) {
      $pdo->prepare("DELETE FROM legislacao_relacoes WHERE id=:id")->execute([':id' => $id]);
    }
    header("Location:/arapiraca/admin_legislacao.php?reopen=$origem&tab=rel&msg=Relacionada+removida");
    exit;

    /* -------- API do painel público (com votação/leitura/fila) -------- */
  case 'status':
    $sid = (int)($_GET['sessao_id'] ?? 0);
    if (!$sid) {
      $sid = (int)$pdo->query("SELECT sessao_id FROM sessao_materias WHERE status='votacao_aberta' ORDER BY id DESC LIMIT 1")->fetchColumn();
    }
    if (!$sid) {
      $sid = (int)$pdo->query("SELECT id FROM sessoes WHERE status='ativa' ORDER BY data_sessao DESC, id DESC LIMIT 1")->fetchColumn();
    }
    if (!$sid) {
      $sid = (int)$pdo->query("SELECT id FROM sessoes WHERE status <> 'encerrada' ORDER BY data_sessao DESC, id DESC LIMIT 1")->fetchColumn();
    }

    if ($sid) {
      $s = $pdo->prepare("SELECT id, numero, tipo, data_sessao, status FROM sessoes WHERE id=:id");
      $s->execute([':id' => $sid]);
      $sessao = $s->fetch();

      $m = $pdo->prepare("
        SELECT sm.id,
               m.titulo,
               m.descricao,
               u.nome   AS autor_nome,
               u.partido AS autor_partido
        FROM sessao_materias sm
        JOIN materias m      ON m.id = sm.materia_id
        LEFT JOIN usuarios u ON u.id = m.autor_id
        WHERE sm.sessao_id=:s AND sm.status='votacao_aberta'
        ORDER BY sm.ordem ASC, sm.id ASC
        LIMIT 1
      ");
      $m->execute([':s' => $sid]);
      $materia = $m->fetch();

      $leitura_info = leitura_get($sid);
      if (!$materia && $leitura_info && $leitura_info['sm_id'] > 0) {
        $m2 = $pdo->prepare("
          SELECT sm.id,
                 m.titulo,
                 m.descricao,
                 u.nome   AS autor_nome,
                 u.partido AS autor_partido
          FROM sessao_materias sm
          JOIN materias m      ON m.id = sm.materia_id
          LEFT JOIN usuarios u ON u.id = m.autor_id
          WHERE sm.sessao_id=:s AND sm.id=:mid
          LIMIT 1
        ");
        $m2->execute([':s' => $sid, ':mid' => $leitura_info['sm_id']]);
        $materia = $m2->fetch() ?: null;
      }

      $parcial = ['favor' => 0, 'contra' => 0, 'abstencao' => 0];
      $mid = 0;
      if ($materia) {
        $mid = (int)$materia['id'];
        $q = $pdo->prepare("
            SELECT v.voto, COUNT(*) AS qtd
            FROM votos v
            JOIN usuarios u ON u.id = v.vereador_id AND COALESCE(u.eh_presidente,0)=0
            WHERE v.sessao_materia_id=:m
            GROUP BY v.voto
        ");
        $q->execute([':m' => $mid]);
        foreach ($q as $row) {
          $parcial[$row['voto']] = (int)$row['qtd'];
        }
      } else {
        $materia = null;
      }

      $falaStmt = $pdo->prepare("
        SELECT pf.id,
               pf.tempo_solicitado,
               UNIX_TIMESTAMP(pf.tempo_inicio) AS started_at,
               u.nome,
               u.foto
        FROM pedidos_fala pf
        JOIN usuarios u ON u.id = pf.vereador_id
        WHERE pf.sessao_id=:s AND pf.status='autorizada'
        ORDER BY pf.id DESC
        LIMIT 1
      ");
      $falaStmt->execute([':s' => $sid]);
      $fala = $falaStmt->fetch() ?: null;

      $filaStmt = $pdo->prepare("
        SELECT pf.id, pf.status, pf.tempo_solicitado,
               UNIX_TIMESTAMP(pf.tempo_inicio) AS started_at,
               u.nome, u.foto
        FROM pedidos_fala pf
        JOIN usuarios u ON u.id = pf.vereador_id
        WHERE pf.sessao_id=:s
          AND pf.status IN ('pendente','autorizada')
        ORDER BY CASE WHEN pf.status='autorizada' THEN 0 ELSE 1 END,
                 pf.id ASC
      ");
      $filaStmt->execute([':s' => $sid]);
      $fila = [];
      foreach ($filaStmt as $row) {
        $fila[] = [
          'id'               => (int)$row['id'],
          'status'           => $row['status'],
          'tempo_solicitado' => (int)$row['tempo_solicitado'],
          'started_at'       => (int)$row['started_at'],
          'nome'             => $row['nome'],
          'foto'             => $row['foto'] ? ('/arapiraca/' . ltrim($row['foto'], '/')) : '/arapiraca/assets/avatar.png',
        ];
      }

      $p = $pdo->prepare("
        SELECT u.nome,
               u.foto,
               COALESCE(u.eh_presidente,0) AS eh_presidente,
               COALESCE(q.presente,0) AS presente,
               v.voto,
               COALESCE(v.is_secreto,0) AS is_secreto
        FROM usuarios u
        LEFT JOIN quorum q ON q.vereador_id=u.id AND q.sessao_id=:s
        LEFT JOIN votos  v ON v.vereador_id=u.id AND v.sessao_materia_id=:m
        WHERE u.tipo_usuario='vereador' AND u.ativo=1
        ORDER BY u.nome
      ");
      $p->execute([':s' => $sid, ':m' => $mid]);
      $pres = [];
      $presentes = 0;
      foreach ($p as $row) {
        $presentes += ((int)$row['presente'] === 1) ? 1 : 0;
        $foto_rel = $row['foto'] ? ('/arapiraca/' . ltrim($row['foto'], '/')) : '/arapiraca/assets/avatar.png';
        $is_pres  = (int)$row['eh_presidente'] === 1;

        $pres[] = [
          'nome'         => $row['nome'],
          'foto'         => $foto_rel,
          'presente'     => (int)$row['presente'],
          'eh_presidente' => $is_pres ? 1 : 0,
          'nao_vota'     => $is_pres ? 1 : 0,
          'voto'         => ($is_pres || (int)$row['is_secreto'] === 1) ? null : ($row['voto'] ?? null)
        ];
      }

      $totais = [
        'vereadores' => (int)$pdo->query("SELECT COUNT(*) FROM usuarios WHERE tipo_usuario='vereador' AND ativo=1")->fetchColumn(),
        'presentes'  => $presentes
      ];

      $nowEpoch = (int)$pdo->query("SELECT UNIX_TIMESTAMP(NOW())")->fetchColumn();

      if ($fala) {
        $fala['foto'] = $fala['foto'] ? ('/arapiraca/' . ltrim($fala['foto'], '/')) : '/arapiraca/assets/avatar.png';
        $fala['started_at'] = (int)$fala['started_at'];
        $fala['tempo_solicitado'] = (int)$fala['tempo_solicitado'];
      }

      // ===== MELHORIA: incluir estado do APARTE no JSON do painel público =====
      $aparteInfo = null;
      $ap = aparte_get($sid);
      if ($ap && $ap['aparte_id'] > 0) {
        $aparteDuracaoSeg = 2 * 60; // 2 minutos de aparte
        $elapsedAparte    = max(0, $nowEpoch - (int)$ap['aparte_started_at']);
        $restanteAparte   = max(0, $aparteDuracaoSeg - $elapsedAparte);

        $stAv = $pdo->prepare("SELECT nome, foto FROM usuarios WHERE id=:id");
        $stAv->execute([':id' => $ap['aparte_vereador_id']]);
        $av = $stAv->fetch();

        $aparteInfo = [
          'principal_pedido_id' => (int)$ap['principal_id'],
          'aparte_pedido_id'    => (int)$ap['aparte_id'],
          'aparte_vereador_id'  => (int)$ap['aparte_vereador_id'],
          'aparte_nome'         => $av['nome'] ?? null,
          'aparte_foto'         => isset($av['foto']) && $av['foto']
            ? ('/arapiraca/' . ltrim($av['foto'], '/'))
            : '/arapiraca/assets/avatar.png',
          'principal_restante'  => (int)$ap['principal_restante'],
          'aparte_restante'     => $restanteAparte,
          'aparte_started_at'   => (int)$ap['aparte_started_at']
        ];
      }

      json_out([
        'sessao'     => $sessao,
        'materia'    => $materia,
        'parcial'    => $parcial,
        'presencas'  => $pres,
        'totais'     => $totais,
        'fala'       => $fala,
        'fila'       => $fila,
        'server_now' => $nowEpoch,
        'leitura'    => $leitura_info,
        'aparte'     => $aparteInfo
      ]);
    } else {
      json_out(['sessao' => null]);
    }
    break;

  /* -------- Status dos pedidos de voz (operador, polling) -------- */
  case 'voz_status':
    require_operador();
    $sid = (int)($_GET['sessao_id'] ?? 0);
    if (!$sid) {
      json_out(['ok' => false, 'err' => 'missing sessao']);
    }

    $qAnd = $pdo->prepare("
      SELECT pf.id, pf.tempo_solicitado,
             UNIX_TIMESTAMP(pf.tempo_inicio) AS started_at,
             DATE_FORMAT(pf.tempo_inicio, '%Y-%m-%d %H:%i:%s') AS tempo_inicio,
             u.nome, u.foto
      FROM pedidos_fala pf
      JOIN usuarios u ON u.id = pf.vereador_id
      WHERE pf.sessao_id = :s AND pf.status = 'autorizada'
      ORDER BY pf.tempo_inicio DESC
      LIMIT 1
    ");
    $qAnd->execute([':s' => $sid]);
    $and = $qAnd->fetch() ?: null;
    if ($and) {
      $and['foto'] = $and['foto'] ? ('/arapiraca/' . ltrim($and['foto'], '/')) : '/arapiraca/assets/avatar.png';
      $and['tempo_solicitado'] = (int)$and['tempo_solicitado'];
      $and['started_at'] = (int)$and['started_at'];
    }

    $qPend = $pdo->prepare("
      SELECT pf.id, pf.tempo_solicitado, COALESCE(pf.observacoes,'') AS observacoes,
             u.nome, u.foto
      FROM pedidos_fala pf
      JOIN usuarios u ON u.id = pf.vereador_id
      WHERE pf.sessao_id = :s AND pf.status = 'pendente'
      ORDER BY pf.id ASC
    ");
    $qPend->execute([':s' => $sid]);
    $pend = [];
    foreach ($qPend as $r) {
      $pend[] = [
        'id' => (int)$r['id'],
        'tempo_solicitado' => (int)$r['tempo_solicitado'],
        'observacoes' => $r['observacoes'],
        'nome' => $r['nome'],
        'foto' => $r['foto'] ? ('/arapiraca/' . ltrim($r['foto'], '/')) : '/arapiraca/assets/avatar.png'
      ];
    }

    $qHist = $pdo->prepare("
      SELECT pf.id, pf.status, pf.tempo_solicitado,
             DATE_FORMAT(pf.tempo_inicio, '%Y-%m-%d %H:%i:%s') AS tempo_inicio,
             DATE_FORMAT(pf.tempo_fim,     '%Y-%m-%d %H:%i:%s') AS tempo_fim,
             u.nome
      FROM pedidos_fala pf
      JOIN usuarios u ON u.id = pf.vereador_id
      WHERE pf.sessao_id = :s AND pf.status IN ('finalizada','cancelada')
      ORDER BY pf.id DESC
      LIMIT 20
    ");
    $qHist->execute([':s' => $sid]);
    $hist = [];
    foreach ($qHist as $r) {
      $hist[] = [
        'id' => (int)$r['id'],
        'status' => $r['status'],
        'tempo_solicitado' => (int)$r['tempo_solicitado'],
        'tempo_inicio' => $r['tempo_inicio'],
        'tempo_fim' => $r['tempo_fim'],
        'nome' => $r['nome']
      ];
    }

    $nowEpoch = (int)$pdo->query("SELECT UNIX_TIMESTAMP(NOW())")->fetchColumn();

    // ===== MELHORIA: incluir estado do APARTE também no polling do operador =====
    $aparteInfo = null;
    $ap = aparte_get($sid);
    if ($ap && $ap['aparte_id'] > 0) {
      $aparteDuracaoSeg = 2 * 60;
      $elapsedAparte    = max(0, $nowEpoch - (int)$ap['aparte_started_at']);
      $restanteAparte   = max(0, $aparteDuracaoSeg - $elapsedAparte);

      $stAv = $pdo->prepare("SELECT nome, foto FROM usuarios WHERE id=:id");
      $stAv->execute([':id' => $ap['aparte_vereador_id']]);
      $av = $stAv->fetch();

      $aparteInfo = [
        'principal_pedido_id' => (int)$ap['principal_id'],
        'aparte_pedido_id'    => (int)$ap['aparte_id'],
        'aparte_vereador_id'  => (int)$ap['aparte_vereador_id'],
        'aparte_nome'         => $av['nome'] ?? null,
        'aparte_foto'         => isset($av['foto']) && $av['foto']
          ? ('/arapiraca/' . ltrim($av['foto'], '/'))
          : '/arapiraca/assets/avatar.png',
        'principal_restante'  => (int)$ap['principal_restante'],
        'aparte_restante'     => $restanteAparte,
        'aparte_started_at'   => (int)$ap['aparte_started_at']
      ];
    }

    json_out([
      'ok' => true,
      'sessao_id' => $sid,
      'andamento' => $and,
      'pendentes' => $pend,
      'historico' => $hist,
      'server_now' => $nowEpoch,
      'aparte' => $aparteInfo
    ]);
    break;

  /* ==================== MATÉRIAS (CRUD simples + vínculo opcional) ==================== */

  case 'mat_info':
    require_operador();
    $id = (int)($_GET['id'] ?? 0);
    if (!$id) {
      http_response_code(400);
      exit('missing');
    }
    $q = $pdo->prepare("SELECT * FROM materias WHERE id=:id");
    $q->execute([':id' => $id]);
    $row = $q->fetch();
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode(['ok' => (bool)$row, 'row' => $row], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;

  case 'mat_salvar':
    require_operador();
    if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
      http_response_code(405);
      exit('method not allowed');
    }

    $id       = (int)($_POST['id'] ?? 0);
    $titulo   = trim($_POST['titulo'] ?? '');
    $tipo     = trim($_POST['tipo'] ?? 'Projeto de Lei');
    $numero   = trim($_POST['numero'] ?? '');
    $ano      = (int)($_POST['ano'] ?? date('Y'));
    $autor_id = (int)($_POST['autor_id'] ?? 0);
    $descr    = trim($_POST['descricao'] ?? '');
    $sessao_id = (int)($_POST['sessao_id'] ?? 0);

    $pdfFile = null;
    if (!empty($_FILES['anexo_pdf'])) {
      $pdfFile = $_FILES['anexo_pdf'];
    } elseif (!empty($_FILES['pdf'])) {
      $pdfFile = $_FILES['pdf'];
    }

    if ($titulo === '' || $autor_id <= 0) {
      header('Location:/arapiraca/admin_materias.php?f=abertas&msg=' . urlencode('Preencha título e propositor.'));
      exit;
    }

    $ok = $pdo->prepare("SELECT COUNT(*) FROM usuarios WHERE id=:id AND tipo_usuario IN ('vereador','proponente') AND ativo=1");
    $ok->execute([':id' => $autor_id]);
    if (!$ok->fetchColumn()) {
      header('Location:/arapiraca/admin_materias.php?f=abertas&msg=' . urlencode('Propositor inválido ou inativo.'));
      exit;
    }

    try {
      if ($id) {
        $qCur = $pdo->prepare("SELECT anexo_pdf FROM materias WHERE id=:id");
        $qCur->execute([':id' => $id]);
        $oldPdf = $qCur->fetchColumn();

        $newPdf = $oldPdf;
        if ($pdfFile && ($pdfFile['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_NO_FILE) {
          $newPdf = save_materia_pdf($pdfFile, $oldPdf);
        }

        $pdo->prepare("
            UPDATE materias
               SET numero=:n, ano=:a, tipo=:t, titulo=:ti, descricao=:d, autor_id=:au, anexo_pdf=:pdf
             WHERE id=:id
        ")->execute([
          ':n' => $numero,
          ':a' => $ano,
          ':t' => $tipo,
          ':ti' => $titulo,
          ':d' => $descr,
          ':au' => $autor_id,
          ':pdf' => $newPdf,
          ':id' => $id
        ]);

        $materia_id = $id;
        $msg = 'Matéria atualizada.';
      } else {
        $pdo->prepare("INSERT INTO materias (numero, ano, tipo, titulo, descricao, autor_id, anexo_pdf)
                       VALUES (:n,:a,:t,:ti,:d,:au,NULL)")
          ->execute([':n' => $numero, ':a' => $ano, ':t' => $tipo, ':ti' => $titulo, ':d' => $descr, ':au' => $autor_id]);
        $materia_id = (int)$pdo->lastInsertId();
        $msg = 'Matéria criada.';

        if ($pdfFile && ($pdfFile['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_NO_FILE) {
          $saved = save_materia_pdf($pdfFile, null);
          $pdo->prepare("UPDATE materias SET anexo_pdf=:p WHERE id=:id")
            ->execute([':p' => $saved, ':id' => $materia_id]);
        }
      }

      if ($sessao_id > 0) {
        $isAtiva = $pdo->prepare("SELECT COUNT(*) FROM sessoes WHERE id=:s AND status='ativa'");
        $isAtiva->execute([':s' => $sessao_id]);
        if ($isAtiva->fetchColumn()) {
          $pdo->prepare("
            INSERT INTO sessao_materias (sessao_id, materia_id, ordem, status, publicar_site)
            SELECT :s, :m,
                   COALESCE( (SELECT MAX(ordem)+1 FROM sessao_materias WHERE sessao_id=:s), 1 ),
                   'aguardando', 1
            FROM DUAL
            WHERE NOT EXISTS (SELECT 1 FROM sessao_materias WHERE sessao_id=:s AND materia_id=:m)
          ")->execute([':s' => $sessao_id, ':m' => $materia_id]);
          $msg .= ' Vinculada à sessão #' . $sessao_id . '.';
        }
      }

      header('Location:/arapiraca/admin_materias.php?f=abertas&msg=' . urlencode($msg));
      exit;
    } catch (Throwable $e) {
      header('Location:/arapiraca/admin_materias.php?f=abertas&msg=' . urlencode('Erro: ' . $e->getMessage()));
      exit;
    }

  case 'mat_vincular':
    require_operador();
    $mid = (int)($_GET['id'] ?? 0);
    if (!$mid) {
      header('Location:/arapiraca/admin_materias.php?msg=ID+inválido');
      exit;
    }

    $sid = (int)$pdo->query("
              SELECT id FROM sessoes
              WHERE status='ativa'
              ORDER BY data_sessao DESC, id DESC
              LIMIT 1")->fetchColumn();

    if (!$sid) {
      header('Location:/arapiraca/admin_materias.php?f=abertas&msg=' . urlencode('Não há sessão ativa.'));
      exit;
    }

    $ordem = (int)$pdo->query("
                SELECT COALESCE(MAX(ordem),0)+1
                FROM sessao_materias
                WHERE sessao_id={$sid}")->fetchColumn();

    $pdo->prepare("
        INSERT INTO sessao_materias (sessao_id, materia_id, ordem, status, publicar_site)
        SELECT :s, :m, :o, 'aguardando', 1 FROM DUAL
        WHERE NOT EXISTS (SELECT 1 FROM sessao_materias WHERE sessao_id=:s AND materia_id=:m)
    ")->execute([':s' => $sid, ':m' => $mid, ':o' => $ordem]);

    header('Location:/arapiraca/admin_materias.php?f=vinculadas&msg=' . urlencode('Vinculada à sessão #' . $sid . '.'));
    exit;

  case 'mat_desvincular':
    require_operador();
    $mid = (int)($_GET['id'] ?? 0);
    if (!$mid) {
      header('Location:/arapiraca/admin_materias.php?msg=ID+inválido');
      exit;
    }

    $emVotacao = (int)$pdo->query("
        SELECT COUNT(*) FROM sessao_materias
        WHERE materia_id={$mid} AND status='votacao_aberta'")->fetchColumn();
    if ($emVotacao) {
      header('Location:/arapiraca/admin_materias.php?f=vinculadas&msg=' . urlencode('Feche a votação antes de desvincular.'));
      exit;
    }

    $pdo->prepare("
        DELETE FROM sessao_materias
        WHERE materia_id=:m AND status IN('aguardando','inativa')
    ")->execute([':m' => $mid]);

    header('Location:/arapiraca/admin_materias.php?f=abertas&msg=' . urlencode('Matéria desvinculada.'));
    exit;

  case 'mat_excluir':
    require_operador();
    $id = (int)($_GET['id'] ?? 0);
    if (!$id) {
      header('Location:/arapiraca/admin_materias.php?msg=ID+inválido');
      exit;
    }

    $pdo->prepare("DELETE FROM sessao_materias WHERE materia_id=:m")->execute([':m' => $id]);

    $q = $pdo->prepare("SELECT anexo_pdf FROM materias WHERE id=:id");
    $q->execute([':id' => $id]);
    $pdf = $q->fetchColumn();
    if ($pdf) {
      $abs = __DIR__ . '/' . ltrim($pdf, '/\\');
      if (str_starts_with($abs, __DIR__ . '/uploads/materias') && file_exists($abs)) {
        @unlink($abs);
      }
    }

    $pdo->prepare("DELETE FROM materias WHERE id=:id")->execute([':id' => $id]);

    header('Location:/arapiraca/admin_materias.php?msg=' . urlencode('Matéria excluída'));
    exit;

    /* ==================== ATAS (gerar, publicar e CRUD manual) ==================== */

    // Gera a ata em HTML a partir do gerador /ata.php e SALVA na tabela `atas`
    // URL: /arapiraca/actions.php?op=atas_gerar_html&sessao=123
  case 'atas_gerar_html': {
      require_operador();
      $sessao_id = (int)($_GET['sessao'] ?? 0);
      if ($sessao_id <= 0) {
        header('Location:/arapiraca/admin.php');
        exit;
      }

      $_GET['sessao'] = $sessao_id;
      if (!defined('PUBLIC_PORTAL')) define('PUBLIC_PORTAL', true);

      ob_start();
      $try1 = __DIR__ . '/publico/ata.php';
      $try2 = __DIR__ . '/ata.php';
      if (is_file($try1)) {
        require $try1;
      } elseif (is_file($try2)) {
        require $try2;
      } else {
        ob_end_clean();
        header('Location:/arapiraca/admin.php?msg=' . urlencode('Gerador de ata não encontrado'));
        exit;
      }
      $html = ob_get_clean();

      try {
        $q = $pdo->prepare("SELECT id FROM atas WHERE sessao_id=:s LIMIT 1");
        $q->execute([':s' => $sessao_id]);
        $ata_id = (int)($q->fetchColumn() ?: 0);

        if ($ata_id) {
          $st = $pdo->prepare("
          UPDATE atas
             SET titulo = :t,
                 texto_html = :h,
                 pdf_path = NULL,
                 publicar_site = 1,
                 updated_at = NOW()
           WHERE id=:id
        ");
          $st->execute([
            ':t'  => 'Ata da Sessão ' . $sessao_id,
            ':h'  => $html,
            ':id' => $ata_id
          ]);
        } else {
          $st = $pdo->prepare("
          INSERT INTO atas (sessao_id, titulo, texto_html, publicar_site)
          VALUES (:s, :t, :h, 1)
        ");
          $st->execute([
            ':s' => $sessao_id,
            ':t' => 'Ata da Sessão ' . $sessao_id,
            ':h' => $html
          ]);
        }
        header('Location:/arapiraca/admin.php?msg=' . urlencode('Ata salva/atualizada'));
        exit;
      } catch (Throwable $e) {
        header('Location:/arapiraca/admin.php?msg=' . urlencode('Erro ao salvar ata: ' . $e->getMessage()));
        exit;
      }
    }

    // Publicar / Despublicar ata no site (por sessão)
    // URL: /arapiraca/actions.php?op=atas_publicar&sessao=123&flag=1|0
  case 'atas_publicar': {
      require_operador();
      $sessao_id = (int)($_GET['sessao'] ?? 0);
      $flag      = (int)($_GET['flag'] ?? 0) ? 1 : 0;
      if ($sessao_id <= 0) {
        header('Location:/arapiraca/admin.php');
        exit;
      }

      $st = $pdo->prepare("UPDATE atas SET publicar_site=:p, updated_at=NOW() WHERE sessao_id=:s");
      $st->execute([':p' => $flag, ':s' => $sessao_id]);

      header('Location:/arapiraca/admin.php?msg=' . urlencode($flag ? 'Ata publicada' : 'Ata despublicada'));
      exit;
    }

    // CRUD manual de ata (com resumo, HTML e/ou PDF)
    // POST: id?, sessao_id?, titulo*, resumo?, texto_html?, publicar_site?, data_ata?, pdf?
  case 'ata_salvar': {
      require_operador();
      if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
        http_response_code(405);
        exit('method not allowed');
      }

      $id           = (int)($_POST['id'] ?? 0);
      $sessao_id    = trim($_POST['sessao_id'] ?? '');
      $sessao_id    = ($sessao_id === '') ? null : (int)$sessao_id;
      $titulo       = trim($_POST['titulo'] ?? '');
      $resumo       = trim($_POST['resumo'] ?? '');
      $texto_html   = trim($_POST['texto_html'] ?? '');
      $publicar     = (int)($_POST['publicar_site'] ?? 1);
      $data_ata     = $_POST['data_ata'] ?? null;
      if ($data_ata === '') $data_ata = null;

      if ($titulo === '') {
        header('Location:/arapiraca/admin_atas.php?msg=' . urlencode('Informe o título.'));
        exit;
      }

      $hasDataCol = $pdo->query("SHOW COLUMNS FROM atas LIKE 'data_ata'")->rowCount() > 0;

      $pdo->beginTransaction();
      try {
        $pdf_path = null;
        if (!empty($_FILES['pdf']) && ($_FILES['pdf']['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_NO_FILE) {
          $pdf_path = save_ata_pdf($_FILES['pdf'], null);
        }

        if ($id > 0) {
          $cur = $pdo->prepare("SELECT pdf_path FROM atas WHERE id=:id");
          $cur->execute([':id' => $id]);
          $oldPdf = $cur->fetchColumn();
          if (!$pdf_path) $pdf_path = $oldPdf;

          $sql = "UPDATE atas SET sessao_id=:s, titulo=:t, resumo=:r, texto_html=:h, pdf_path=:p, publicar_site=:pub";
          $args = [':s' => $sessao_id, ':t' => $titulo, ':r' => $resumo, ':h' => $texto_html, ':p' => $pdf_path, ':pub' => $publicar, ':id' => $id];
          if ($hasDataCol) {
            $sql .= ", data_ata=:d";
            $args[':d'] = $data_ata;
          }
          $sql .= ", updated_at=NOW() WHERE id=:id";
          $pdo->prepare($sql)->execute($args);
        } else {
          $cols = "sessao_id, titulo, resumo, texto_html, pdf_path, publicar_site, created_at, updated_at";
          $vals = ":s, :t, :r, :h, :p, :pub, NOW(), NOW()";
          $args = [':s' => $sessao_id, ':t' => $titulo, ':r' => $resumo, ':h' => $texto_html, ':p' => $pdf_path, ':pub' => $publicar];

          if ($hasDataCol) {
            $cols = "data_ata, " . $cols;
            $vals = ":d, " . $vals;
            $args[':d'] = $data_ata;
          }

          $pdo->prepare("INSERT INTO atas ($cols) VALUES ($vals)")->execute($args);
        }

        $pdo->commit();
        header('Location:/arapiraca/admin_atas.php?msg=' . urlencode('Ata salva.'));
      } catch (Throwable $e) {
        $pdo->rollBack();
        header('Location:/arapiraca/admin_atas.php?msg=' . urlencode('Erro: ' . $e->getMessage()));
      }
      exit;
    }

    // Toggle rápido por ID (publicar/despublicar)
  case 'ata_toggle_publicar': {
      require_operador();
      $id = (int)($_GET['id'] ?? 0);
      if ($id <= 0) {
        header('Location:/arapiraca/admin_atas.php?msg=ID+inválido');
        exit;
      }
      $pdo->prepare("UPDATE atas SET publicar_site = 1 - COALESCE(publicar_site,0), updated_at=NOW() WHERE id=:id")
        ->execute([':id' => $id]);
      header('Location:/arapiraca/admin_atas.php?msg=' . urlencode('Atualizado.'));
      exit;
    }

    // Excluir ata (por ID ou por sessão) — apaga também o PDF do disco
    // URL por ID:     /arapiraca/actions.php?op=ata_excluir&id=123
    // URL por sessão: /arapiraca/actions.php?op=ata_excluir&sessao=456
  case 'ata_excluir': {
      require_operador();

      $id = (int)($_GET['id'] ?? 0);
      $sessao_id = (int)($_GET['sessao'] ?? 0);

      // Se não veio ID, tenta achar pela sessão
      if ($id <= 0 && $sessao_id > 0) {
        $st = $pdo->prepare("SELECT id FROM atas WHERE sessao_id=:s LIMIT 1");
        $st->execute([':s' => $sessao_id]);
        $id = (int)($st->fetchColumn() ?: 0);
      }

      if ($id <= 0) {
        header('Location:/arapiraca/admin_atas.php?msg=' . urlencode('ID inválido'));
        exit;
      }

      // Busca caminho do PDF (se existir) para apagar do disco
      $q = $pdo->prepare("SELECT pdf_path FROM atas WHERE id=:id");
      $q->execute([':id' => $id]);
      $pdf = $q->fetchColumn();

      if ($pdf) {
        $abs = __DIR__ . '/' . ltrim($pdf, '/\\');
        // apaga somente se estiver na pasta correta e existir
        if (str_starts_with($abs, __DIR__ . '/uploads/atas') && file_exists($abs)) {
          @unlink($abs);
        }
      }

      // Exclui o registro da ata
      $pdo->prepare("DELETE FROM atas WHERE id=:id")->execute([':id' => $id]);

      header('Location:/arapiraca/admin_atas.php?msg=' . urlencode('Ata excluída'));
      exit;
    }


    /* ==================== LEITURA (toggle) ==================== */
  case 'leitura_toggle': {
      require_operador();
      $sm_id     = (int)($_GET['id'] ?? 0);       // id de sessao_materias
      $sessao_id = (int)($_GET['sessao_id'] ?? 0);
      if (!$sm_id || !$sessao_id) exit('missing');

      $st = $pdo->prepare("SELECT COUNT(*) FROM sessao_materias WHERE id=:id AND sessao_id=:s");
      $st->execute([':id' => $sm_id, ':s' => $sessao_id]);
      if (!(int)$st->fetchColumn()) {
        header("Location:/arapiraca/admin_materia_nova.php?sessao={$sessao_id}&err=" . urlencode('Matéria não pertence à sessão.'));
        exit;
      }

      $cur = leitura_get($sessao_id);
      if ($cur && (int)$cur['sm_id'] === $sm_id) {
        leitura_clear($sessao_id);
        $msg = 'Leitura desligada.';
      } else {
        leitura_set($sessao_id, $sm_id);
        $msg = 'Leitura ligada para a matéria.';
      }

      header("Location:/arapiraca/admin_materia_nova.php?sessao={$sessao_id}&msg=" . urlencode($msg));
      exit;
    }

    /* ==================== VEREADOR – STATUS TEMPO REAL (para polling da UI) ==================== */
  case 'vereador_status':
    if (empty($_SESSION['user_id'])) {
      http_response_code(401);
      exit('unauth');
    }
    if (($_SESSION['tipo'] ?? '') !== 'vereador') {
      http_response_code(403);
      exit('forbidden');
    }

    header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
    header('Pragma: no-cache');
    header('Content-Type: application/json; charset=utf-8');

    $sessao_id = (int)($_GET['sessao_id'] ?? 0);

    if ($sessao_id <= 0) {
      $sessao_id = (int)$pdo->query("
        SELECT sm.sessao_id
          FROM sessao_materias sm
         WHERE sm.status='votacao_aberta'
         ORDER BY sm.id DESC
         LIMIT 1
      ")->fetchColumn();

      if ($sessao_id <= 0) {
        $sessao_id = (int)$pdo->query("
          SELECT id FROM sessoes
           WHERE status='ativa'
           ORDER BY data_sessao DESC, id DESC
           LIMIT 1
        ")->fetchColumn();
      }

      if ($sessao_id <= 0) {
        $sessao_id = (int)$pdo->query("
          SELECT id FROM sessoes
           WHERE status <> 'encerrada'
           ORDER BY data_sessao DESC, id DESC
           LIMIT 1
        ")->fetchColumn();
      }
    }

    if ($sessao_id <= 0) {
      echo json_encode(['ok' => true, 'sessao_id' => null, 'sm_id' => null], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
      exit;
    }

    $q = $pdo->prepare("
      SELECT sm.id AS sm_id, m.titulo, m.descricao
        FROM sessao_materias sm
        JOIN materias m ON m.id = sm.materia_id
       WHERE sm.sessao_id = :s AND sm.status = 'votacao_aberta'
       ORDER BY sm.ordem ASC, sm.id ASC
       LIMIT 1
    ");
    $q->execute([':s' => $sessao_id]);
    $mat = $q->fetch();

    if (!$mat) {
      echo json_encode([
        'ok' => true,
        'sessao_id' => $sessao_id,
        'sm_id' => null,
        'materia' => null,
        'precisa_presenca' => false,
        'ja_votou' => false,
        'voto' => null
      ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
      exit;
    }

    $sm_id = (int)$mat['sm_id'];
    $vereador_id = (int)$_SESSION['user_id'];

    $stP = $pdo->prepare("SELECT COALESCE(presente,0) FROM quorum WHERE sessao_id=:s AND vereador_id=:v");
    $stP->execute([':s' => $sessao_id, ':v' => $vereador_id]);
    $presente = (int)$stP->fetchColumn() === 1;

    $stV = $pdo->prepare("SELECT voto FROM votos WHERE sessao_materia_id=:m AND vereador_id=:v LIMIT 1");
    $stV->execute([':m' => $sm_id, ':v' => $vereador_id]);
    $voto = $stV->fetchColumn();
    $ja_votou = ($voto !== false && $voto !== null);

    echo json_encode([
      'ok' => true,
      'sessao_id' => $sessao_id,
      'sm_id' => $sm_id,
      'materia' => [
        'titulo' => $mat['titulo'] ?? '',
        'descricao' => $mat['descricao'] ?? ''
      ],
      'precisa_presenca' => !$presente,
      'ja_votou' => $ja_votou,
      'voto' => $ja_votou ? $voto : null
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;

    /* -------- Default -------- */
  default:
    http_response_code(400);
    echo "op inválida";
    exit;
}
