<?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;
  }
}

/* ---------------- 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 Legislação ---------------- */
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;
}

/* ----------------------- 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);
}

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

  /* -------- Sessão do usuário -------- */
  case 'logout':
    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]);
    // limpa eventual leitura ligada
    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]);

    // >>> NOVO: encerra eventual leitura ligada nesta sessão
    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'] ?? '');

    // Confere vínculo e status
    $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 {
        // Votação não está aberta -> não pode mudar
        header('Location:/arapiraca/vereador.php?sessao=' . $sid . '&msg=votacao_encerrada_sem_alteracao');
        exit;
      }
    } else {
      // Não há voto ainda -> inserir (somente faz sentido se estiver aberta)
      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);   // minutos a somar
    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;

  /* ---------------- 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 {
      // Se marcou presidente e é vereador, zera os demais
      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 ==================== */

  /* Criar/editar legislatura */
  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;
    }

  /* Ativar/Inativar */
  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;

  /* Excluir legislatura */
  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;

  /* Carrega dados p/ modal (row + vereadores + mesa) */
  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']);

    // vereadores vinculados
    $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();

    // mesa diretora (INCLUI sessao_legislativa)
    $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]);

  /* Adicionar vereador à legislatura */
  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;
    }

    // confere se é vereador ativo
    $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;
    }

    // evita duplicidade
    $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;

  /* Remover vereador da legislatura */
  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;

  /* Adicionar membro à mesa (com sessão legislativa opcional) */
  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;
    }

    // garantir 1 ocupante por cargo (se esse for o critério)
    $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;

  /* Remover membro da mesa */
  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;

  //* Adicionar membro à mesa */
  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; } // opcional

    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;
    }

    // garantir 1 ocupante por cargo (se esse for o seu critério)
    $pdo->prepare("DELETE FROM legislatura_mesa WHERE legislatura_id=:l AND cargo=:c")
        ->execute([':l' => $leg_id, ':c' => $cargo]);

    // cria já com a sessão legislativa (pode ser NULL)
    $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;

  /* ==================== COMISSÕES ==================== */
  // Criar/editar comissão
  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;

  // Ativar/Inativar comissão
  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;

  // Excluir comissão (FK remove membros)
  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;

  // Info para modal (row + membros)
  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]);

  // Adicionar membro
  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;
    }

    // valida vereador
    $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;
    }

    // garantir apenas um ocupante por cargo “exclusivo”
    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]);
    }

    // inserir se não existir
    $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;

  // Remover membro
  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 ==================== */

  /* Criar/editar norma */
  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;
    }

  /* Excluir norma */
  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;

  /* Info (row + relações) */
  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]);

  /* Busca para relacionar */
  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]);

  /* Adicionar/Remover relação */
  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 (com FOTO + descrição + proponente + orador + 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();

      // Matéria em votação (prioridade no painel)
      $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();

      // Se não há votação aberta, checa LEITURA ligada para esta sessão
      $leitura_info = leitura_get($sid); // ['sm_id'=>..., 'started_at'=>...]
      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'];

        // Exclui presidente da parcial
        $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;
      }

      // Orador atual
      $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;

      // Fila (pendentes + autorizado no topo)
      $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',
        ];
      }

      // Quórum + votos (com flag de presidente)
      $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,
          // nunca expõe voto do presidente nem voto secreto
          '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'];
      }

      json_out([
        'sessao'     => $sessao,
        'materia'    => $materia,
        'parcial'    => $parcial,
        'presencas'  => $pres,
        'totais'     => $totais,
        'fala'       => $fala,
        'fila'       => $fila,
        'server_now' => $nowEpoch,
        // informação de leitura para o painel público (sm_id e timestamp)
        'leitura'    => $leitura_info
      ]);

    } 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']); }

    // Em andamento (autorizada)
    $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'];
    }

    // Pendentes
    $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'
      ];
    }

    // Histórico
    $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();

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

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

  /* Info (se precisar buscar via AJAX no futuro) */
  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);

    // aceita 'anexo_pdf' (preferível) ou 'pdf'
    $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;
    }

  /* Vincular à ÚLTIMA sessão ATIVA (status=aguardando) */
  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;

  /* Desvincular (remove vínculos não finalizados) */
  case 'mat_desvincular':
    require_operador();
    $mid = (int)($_GET['id'] ?? 0);
    if (!$mid) {
      header('Location:/arapiraca/admin_materias.php?msg=ID+inválido');
      exit;
    }

    // bloqueia se estiver em votação aberta
    $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;

  /* Excluir (apaga vínculos primeiro) */
  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 e publicar) ==================== */

  // 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; }

    // Monta HTML capturando a saída do gerador
    $_GET['sessao'] = $sessao_id;
    // Se o seu ata.php exige login, não tem problema (você é operador). Se
    // quiser liberar textos próprios para público, pode definir PUBLIC_PORTAL:
    if (!defined('PUBLIC_PORTAL')) define('PUBLIC_PORTAL', true);

    ob_start();
    $try1 = __DIR__ . '/publico/ata.php';  // caso exista um gerador em /publico
    $try2 = __DIR__ . '/ata.php';          // gerador padrão

    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();

    // Insere/atualiza na tabela `atas`
    try {
      // tenta atualizar se já existe
      $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
  // 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;
  }

  /* ==================== LEITURA (toggle) ==================== */
  // Liga/desliga a “leitura” de uma matéria para o PAINEL PÚBLICO
  // URL: /arapiraca/actions.php?op=leitura_toggle&id=<sm_id>&sessao_id=<sid>
  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');

    // Confere se pertence à sessão
    $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); // desliga
      $msg = 'Leitura desligada.';
    } else {
      leitura_set($sessao_id, $sm_id); // liga para esta matéria
      $msg = 'Leitura ligado para a matéria.';
    }

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

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