<?php
// includes/acl.php

if (!function_exists('pac_norm_path')) {
  function pac_norm_path(string $p): string {
    $p = str_replace('\\','/',$p);
    $p = preg_replace('#//+#','/',$p);
    return rtrim($p,'/');
  }
}
if (!function_exists('pac_table_exists')) {
  function pac_table_exists(mysqli $con, string $table): bool {
    $t = mysqli_real_escape_string($con,$table);
    $r = mysqli_query($con,"SHOW TABLES LIKE '$t'");
    return ($r && mysqli_num_rows($r)>0);
  }
}
if (!function_exists('pac_col_exists')) {
  function pac_col_exists(mysqli $con, string $table, string $col): bool {
    $t = mysqli_real_escape_string($con,$table);
    $c = mysqli_real_escape_string($con,$col);
    $r = mysqli_query($con,"SHOW COLUMNS FROM `$t` LIKE '$c'");
    return ($r && mysqli_num_rows($r)>0);
  }
}

/* role id resolver */
if (!function_exists('pac_current_role_id')) {
  function pac_current_role_id(
    mysqli $con, int $user_id,
    string $roleTable='jos_admin_roles',
    string $mapTable='jos_admin_users_roles'
  ): ?int {
    if (!pac_table_exists($con,$mapTable) || !pac_table_exists($con,$roleTable)) return null;
    $sql="SELECT ur.role_id
          FROM `$mapTable` ur
          JOIN `$roleTable` r ON r.id=ur.role_id AND r.status=1
          WHERE ur.user_id=? LIMIT 1";
    if(!$st=$con->prepare($sql)) return null;
    $st->bind_param('i',$user_id);
    $st->execute();
    $rid=$st->get_result()->fetch_column();
    $st->close();
    return $rid ? (int)$rid : null;
  }
}

/* paths for menu_link matching */
if (!function_exists('pac_candidate_paths')) {
  function pac_candidate_paths(): array {
    $script  = pac_norm_path($_SERVER['SCRIPT_NAME'] ?? '');
    $reqPath = pac_norm_path(parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH) ?: '');
    $base    = basename($script);
    return array_values(array_unique(array_filter([
      $script, $reqPath, $base,
      preg_replace('#^/beta#','',$script),
      preg_replace('#^/beta#','',$reqPath),
    ])));
  }
}

/* view access (legacy “any mapping to menu” – kept for compatibility) */
if (!function_exists('pac_has_menu_access')) {
  function pac_has_menu_access(
    mysqli $con, int $role_id,
    string $roleMenuTable='jos_admin_rolemenus',
    string $menusTable='jos_admin_menus'
  ): bool {
    if (!pac_table_exists($con,$roleMenuTable) || !pac_table_exists($con,$menusTable)) return true;
    $cands = pac_candidate_paths();
    $likes=[]; $types='i'; $vals=[$role_id];
    foreach($cands as $c){
      $likes[]="m.menu_link = ?";    $types.='s'; $vals[]=$c;
      $likes[]="m.menu_link LIKE ?"; $types.='s'; $vals[]='%'.$c;
      $likes[]="m.menu_link LIKE ?"; $types.='s'; $vals[]='%'.$c.'%';
    }
    $sql="SELECT 1
          FROM `$roleMenuTable` rm
          JOIN `$menusTable` m ON m.id=rm.menu_id
          WHERE rm.role_id=? AND m.status=1 AND (".implode(' OR ',$likes).")
          LIMIT 1";
    if(!$st=$con->prepare($sql)) return false;
    $st->bind_param($types, ...$vals);
    $st->execute();
    $ok=(bool)$st->get_result()->fetch_column();
    $st->close();
    return $ok;
  }
}

/* action/view caps from rolemenus (auto-detect column names) */
if (!function_exists('pac_fetch_action_caps')) {
  function pac_fetch_action_caps(
    mysqli $con, int $role_id,
    string $roleMenuTable='jos_admin_rolemenus',
    string $menusTable='jos_admin_menus'
  ): array {
    // defaults (back-compat if columns missing)
    $caps=['view'=>true,'add'=>true,'edit'=>true,'delete'=>true];

    if (!pac_table_exists($con,$roleMenuTable) || !pac_table_exists($con,$menusTable)) return $caps;

    $cols = [
      'view'   => pac_col_exists($con,$roleMenuTable,'can_view')   ? 'can_view'   : (pac_col_exists($con,$roleMenuTable,'allow_view')   ? 'allow_view'   : null),
      'add'    => pac_col_exists($con,$roleMenuTable,'can_add')    ? 'can_add'    : (pac_col_exists($con,$roleMenuTable,'allow_add')    ? 'allow_add'    : null),
      'edit'   => pac_col_exists($con,$roleMenuTable,'can_edit')   ? 'can_edit'   : (pac_col_exists($con,$roleMenuTable,'allow_edit')   ? 'allow_edit'   : null),
      'delete' => pac_col_exists($con,$roleMenuTable,'can_delete') ? 'can_delete' : (pac_col_exists($con,$roleMenuTable,'allow_delete') ? 'allow_delete' : null),
    ];
    // if none exist, keep defaults
    if (!$cols['view'] && !$cols['add'] && !$cols['edit'] && !$cols['delete']) return $caps;

    $cands = pac_candidate_paths();

    $selects=[];
    foreach(['view','add','edit','delete'] as $k){
      $selects[] = $cols[$k] ? "rm.`{$cols[$k]}` AS `$k`" : "1 AS `$k`";
    }
    $select_sql=implode(',',$selects);

    $likes=[]; $types='i'; $vals=[$role_id];
    foreach($cands as $c){
      $likes[]="m.menu_link = ?";    $types.='s'; $vals[]=$c;
      $likes[]="m.menu_link LIKE ?"; $types.='s'; $vals[]='%'.$c;
      $likes[]="m.menu_link LIKE ?"; $types.='s'; $vals[]='%'.$c.'%';
    }

    $sql="SELECT $select_sql
         FROM `$roleMenuTable` rm
         JOIN `$menusTable` m ON m.id=rm.menu_id
         WHERE rm.role_id=? AND m.status=1 AND (".implode(' OR ',$likes).")
         ORDER BY m.id DESC
         LIMIT 1";
    if(!$st=$con->prepare($sql)) return $caps;
    $st->bind_param($types, ...$vals);
    $st->execute();
    if($row=$st->get_result()->fetch_assoc()){
      foreach(['view','add','edit','delete'] as $k){
        $caps[$k] = (int)($row[$k] ?? 1) ? true : false;
      }
    }
    $st->close();
    return $caps;
  }
}

/* main: combine role existence + view mapping + action caps */
if (!function_exists('pac_menu_caps')) {
  function pac_menu_caps(mysqli $con, array $opts=[]): array {
    $roleTable     = $opts['roleTable']     ?? 'jos_admin_roles';
    $mapTable      = $opts['mapTable']      ?? 'jos_admin_users_roles';
    $roleMenuTable = $opts['roleMenuTable'] ?? 'jos_admin_rolemenus';
    $menusTable    = $opts['menusTable']    ?? 'jos_admin_menus';
    $me            = $_SESSION['admin_user'] ?? [];
    $user_id       = (int)($opts['user_id'] ?? ($me['id'] ?? 0));

    if ($user_id <= 0) {
      return ['has_access'=>false,'view'=>false,'add'=>false,'edit'=>false,'delete'=>false,'role_id'=>null];
    }
    $rid = pac_current_role_id($con, $user_id, $roleTable, $mapTable);
    if ($rid === null) {
      return ['has_access'=>false,'view'=>false,'add'=>false,'edit'=>false,'delete'=>false,'role_id'=>null];
    }

    // legacy “has menu” + fine-grained view flag
    $mapped  = pac_has_menu_access($con, $rid, $roleMenuTable, $menusTable);
    $caps    = pac_fetch_action_caps($con, $rid, $roleMenuTable, $menusTable);
    $canView = $mapped && $caps['view']; // both must be true

    return [
      'has_access' => $canView, // alias for compatibility
      'view'       => $canView,
      'add'        => (bool)$caps['add'],
      'edit'       => (bool)$caps['edit'],
      'delete'     => (bool)$caps['delete'],
      'role_id'    => $rid,
    ];
  }
}
