<?php
// access_logs.php — Logs de acesso (datas com input nativo, zebrado, destaque de erros)
$title = 'Logs de acesso';
require_once __DIR__ . '/auth.php';
require_perm('logs.view');
check_csrf();

/* ========================= Helpers ========================= */
function al_has_col(PDO $pdo, string $tbl, string $col): bool {
  static $c=[]; $k="$tbl.$col";
  if(isset($c[$k])) return $c[$k];
  $st=$pdo->prepare("SELECT COUNT(*) FROM information_schema.COLUMNS
                     WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? AND COLUMN_NAME=?");
  $st->execute([$tbl,$col]); return $c[$k]=(bool)$st->fetchColumn();
}
function al_to_sql_date(?string $s): ?string {
  $s=trim((string)$s); if($s==='') return null;
  // dd/mm/aaaa
  if(preg_match('~^(?<d>\d{2})/(?<m>\d{2})/(?<y>\d{4})$~',$s,$m) &&
     checkdate((int)$m['m'],(int)$m['d'],(int)$m['y'])) {
    return sprintf('%04d-%02d-%02d',$m['y'],$m['m'],$m['d']);
  }
  // aaaa-mm-dd
  if(preg_match('~^(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})$~',$s,$m) &&
     checkdate((int)$m['m'],(int)$m['d'],(int)$m['y'])) {
    return $s;
  }
  return null;
}
function al_like(string $s, int $max=120): string {
  $s=trim($s); return $s===''?'':mb_substr($s,0,$max);
}

/* ==================== Schema dinâmico ====================== */
$tbl     = 'access_log';
$tsCol   = null; foreach (['created_at','logged_at','time','timestamp','ts'] as $c) if (al_has_col($pdo,$tbl,$c)) { $tsCol=$c; break; }
if (!$tsCol) $tsCol = 'created_at';
$hasUser = al_has_col($pdo,$tbl,'user_id');
$hasIP   = al_has_col($pdo,$tbl,'ip');
$hasPath = al_has_col($pdo,$tbl,'path') || al_has_col($pdo,$tbl,'route') || al_has_col($pdo,$tbl,'url');
$hasMeth = al_has_col($pdo,$tbl,'method');
$hasNote = al_has_col($pdo,$tbl,'notes');
$statCol = null; foreach (['status_code','http_status','status'] as $c) if (al_has_col($pdo,$tbl,$c)) { $statCol=$c; break; }

/* ======================== Filtros ========================== */
$from_in = trim($_GET['from'] ?? '');
$to_in   = trim($_GET['to']   ?? '');
$from_sql= al_to_sql_date($from_in);
$to_sql  = al_to_sql_date($to_in);

$user_id = (int)($_GET['user'] ?? 0);
$action  = trim($_GET['action'] ?? '');
$q       = al_like($_GET['q'] ?? '');
$onlyErr = ($_GET['only_errors'] ?? '')==='1';

/* Para <input type="date"> precisamos de ISO (aaaa-mm-dd) */
$from_iso = $from_sql ?? '';
$to_iso   = $to_sql   ?? '';

/* ======================== Query ============================ */
$cols = ["lg.`$tsCol` AS logged_at","lg.action","u.name AS user_name"];
if ($hasUser) $cols[] = "lg.user_id";
if ($hasIP)   $cols[] = "lg.ip";
if ($hasMeth) $cols[] = "lg.method";
if ($hasPath) $cols[] = (al_has_col($pdo,$tbl,'path')?'lg.path':(al_has_col($pdo,$tbl,'route')?'lg.route':'lg.url'))." AS path";
if ($hasNote) $cols[] = "lg.notes";
if ($statCol) $cols[] = "lg.`$statCol` AS status_code";

$sql = "SELECT ".implode(',',$cols)." FROM `$tbl` lg LEFT JOIN users u ON u.id=lg.user_id";

$where=[]; $bind=[];
if ($from_sql){ $where[] = "lg.`$tsCol` >= ?"; $bind[] = $from_sql.' 00:00:00'; }
if ($to_sql)  { $where[] = "lg.`$tsCol` <  DATE_ADD(?,INTERVAL 1 DAY)"; $bind[] = $to_sql; }
if ($user_id>0 && $hasUser){ $where[]="lg.user_id=?"; $bind[]=$user_id; }
if ($action!==''){ $where[]="lg.action=?"; $bind[]=$action; }

if ($onlyErr) {
  $errParts = ["lg.action='LOGIN_FAIL'"];
  if ($statCol) $errParts[] = "lg.`$statCol` >= 400";
  $where[] = '('.implode(' OR ',$errParts).')';
}

if ($q!==''){
  $p=[];
  if ($hasUser) $p[]="u.name LIKE ?"; 
  if ($hasIP)   $p[]="lg.ip LIKE ?";
  if ($hasMeth) $p[]="lg.method LIKE ?";
  if ($hasPath) $p[]="(lg.path LIKE ? OR lg.route LIKE ? OR lg.url LIKE ?)";
  if ($hasNote) $p[]="lg.notes LIKE ?";
  if ($statCol) $p[]="CAST(lg.`$statCol` AS CHAR) LIKE ?";
  $where[]='('.implode(' OR ',$p).')';
  if ($hasUser) $bind[]="%$q%";
  if ($hasIP)   $bind[]="%$q%";
  if ($hasMeth) $bind[]="%$q%";
  if ($hasPath){ $bind[]="%$q%"; $bind[]="%$q%"; $bind[]="%$q%"; }
  if ($hasNote) $bind[]="%$q%";
  if ($statCol) $bind[]="%$q%";
}
if ($where) $sql .= ' WHERE '.implode(' AND ',$where);
$sql .= " ORDER BY lg.`$tsCol` DESC LIMIT 1000";

$st=$pdo->prepare($sql); $st->execute($bind); $rows=$st->fetchAll();

/* Seletores */
$users = $hasUser ? $pdo->query("SELECT id,name FROM users WHERE is_active=1 ORDER BY name")->fetchAll() : [];
$actions = ['LOGIN_OK','LOGIN_FAIL','LOGOUT','PAGE'];

include __DIR__ . '/header.php';
?>
<div class="container-fluid">
  <div class="d-flex justify-content-between align-items-center mb-3">
    <h2 class="h5 m-0">Logs de acesso</h2>
    <span class="text-muted small">Retenção: <?= (int)(defined('ACCESS_LOG_RETENTION_DAYS')?ACCESS_LOG_RETENTION_DAYS:180) ?> dias</span>
  </div>

  <!-- Filtros -->
  <form class="row g-2 align-items-end mb-3" method="get" novalidate>
    <div class="col-md-2">
      <label class="form-label">De</label>
      <input type="date" name="from" value="<?= h($from_iso) ?>" class="form-control">
    </div>
    <div class="col-md-2">
      <label class="form-label">Até</label>
      <input type="date" name="to" value="<?= h($to_iso) ?>" class="form-control">
    </div>
    <?php if ($hasUser): ?>
      <div class="col-md-3">
        <label class="form-label">Usuário</label>
        <select name="user" class="form-select">
          <option value="0">(todos os usuários)</option>
          <?php foreach($users as $u): ?>
            <option value="<?= (int)$u['id'] ?>" <?= ((int)$user_id===(int)$u['id'])?'selected':'' ?>><?= h($u['name']) ?></option>
          <?php endforeach; ?>
        </select>
      </div>
    <?php endif; ?>
    <div class="col-md-3">
      <label class="form-label">Ação</label>
      <select name="action" class="form-select">
        <option value="">(todas as ações)</option>
        <?php foreach($actions as $a): ?>
          <option value="<?= h($a) ?>" <?= $action===$a?'selected':'' ?>><?= h($a) ?></option>
        <?php endforeach; ?>
      </select>
    </div>
    <div class="col-md-2">
      <label class="form-label">Somente erros</label>
      <div class="form-check mt-2">
        <input class="form-check-input" type="checkbox" name="only_errors" value="1" id="onlyErr" <?= $onlyErr?'checked':'' ?>>
        <label class="form-check-label" for="onlyErr">Filtrar erros</label>
      </div>
    </div>
    <div class="col-12 col-md-6">
      <label class="form-label">Busca livre</label>
      <input type="text" name="q" value="<?= h($q) ?>" class="form-control"
             placeholder="Usuário, IP, rota, método, status, nível, mensagem…">
    </div>
    <div class="col-12 col-md-6 d-flex gap-2">
      <button class="btn btn-primary flex-fill">Filtrar</button>
      <a class="btn btn-outline-secondary flex-fill" href="<?= base_url('access_logs.php') ?>">Limpar</a>
    </div>
  </form>

  <!-- Tabela -->
  <div class="card border-0 shadow-sm">
    <div class="table-responsive">
      <table class="table table-striped align-middle mb-0">
        <thead>
          <tr>
            <th>Quando</th>
            <?php if ($hasUser): ?><th>Usuário</th><?php endif; ?>
            <th>Ação</th>
            <?php if ($hasIP):   ?><th>IP</th><?php endif; ?>
            <?php if ($hasMeth): ?><th>Método</th><?php endif; ?>
            <?php if ($hasPath): ?><th>Rota</th><?php endif; ?>
            <?php if ($statCol):?><th>Status</th><?php endif; ?>
            <?php if ($hasNote):?><th>Notas</th><?php endif; ?>
          </tr>
        </thead>
        <tbody>
          <?php foreach($rows as $r):
            $isErr = ($r['action'] ?? '')==='LOGIN_FAIL';
            if (!$isErr && isset($r['status_code']) && $r['status_code']!==null) $isErr = ((int)$r['status_code']>=400);
          ?>
            <tr class="<?= $isErr?'table-danger':'' ?>">
              <td><?= br_datetime($r['logged_at'] ?? null) ?></td>
              <?php if ($hasUser): ?><td><?= h($r['user_name'] ?? '—') ?></td><?php endif; ?>
              <td><span class="badge <?= $isErr?'bg-danger':'bg-light text-dark border' ?>"><?= h($r['action'] ?? '—') ?></span></td>
              <?php if ($hasIP):   ?><td><?= h($r['ip'] ?? '—') ?></td><?php endif; ?>
              <?php if ($hasMeth): ?><td><?= h($r['method'] ?? '—') ?></td><?php endif; ?>
              <?php if ($hasPath): ?><td><?= h($r['path'] ?? $r['route'] ?? $r['url'] ?? '—') ?></td><?php endif; ?>
              <?php if ($statCol):?><td><?= h(isset($r['status_code'])?$r['status_code']:'—') ?></td><?php endif; ?>
              <?php if ($hasNote):?><td><?= h($r['notes'] ?? '') ?></td><?php endif; ?>
            </tr>
          <?php endforeach; if(!$rows): ?>
            <tr><td colspan="8" class="text-muted">Sem registros para os filtros aplicados.</td></tr>
          <?php endif; ?>
        </tbody>
      </table>
    </div>
  </div>
</div>

<?php include __DIR__ . '/footer.php'; ?>

