<?php
declare(strict_types=1);

function e(?string $s): string {
    return htmlspecialchars($s ?? '', ENT_QUOTES, 'UTF-8');
}

function redirect(string $path): never {
    header("Location: {$path}");
    exit;
}

function url(string $path): string {
    // $path like '/login.php' or '/index.php?page=dashboard'
    return app_base_url() . $path;
}

function flash_set(string $type, string $msg): void {
    $_SESSION['flash'] = ['type'=>$type, 'msg'=>$msg];
}

function flash_get(): ?array {
    $f = $_SESSION['flash'] ?? null;
    unset($_SESSION['flash']);
    return $f;
}

function now_dt(): string {
    return date('Y-m-d H:i:s');
}

function paginate(array $items, int $page, int $perPage): array {
    $total = count($items);
    $pages = (int)ceil($total / $perPage);
    $page = max(1, min($page, max(1, $pages)));
    $offset = ($page - 1) * $perPage;
    return [
        'items' => array_slice($items, $offset, $perPage),
        'page' => $page,
        'pages' => $pages,
        'total' => $total,
        'per_page' => $perPage,
    ];
}

function csrf_token(): string {
    if (empty($_SESSION['csrf'])) {
        $_SESSION['csrf'] = bin2hex(random_bytes(16));
    }
    return $_SESSION['csrf'];
}

function csrf_check(): void {
    $t = $_POST['_csrf'] ?? '';
    if (!$t || !hash_equals($_SESSION['csrf'] ?? '', $t)) {
        http_response_code(419);
        die('CSRF token mismatch.');
    }
}

if (!function_exists('csrf_verify')) {
  function csrf_verify(): void {
    csrf_check();
  }
}


if (!function_exists('owner_label')) {
  function owner_label(string $type, int $id): string {
    if ($type === 'oasis') {
      $r = db_one("SELECT code,name FROM oases WHERE id=?", [$id]);
      return $r ? ("واحة: " . $r['name'] . " (" . $r['code'] . ")") : "واحة: #{$id}";
    }
    if ($type === 'falaj') {
      $r = db_one("SELECT code,name FROM aflaj WHERE id=?", [$id]);
      return $r ? ("فلج: " . $r['name'] . " (" . $r['code'] . ")") : "فلج: #{$id}";
    }
    if ($type === 'farm') {
      $r = db_one("SELECT code,owner_name FROM farms WHERE id=?", [$id]);
      $nm = $r['owner_name'] ?? '';
      return $r ? ("مزرعة: " . ($nm ?: 'بدون مالك') . " (" . $r['code'] . ")") : "مزرعة: #{$id}";
    }
    return $type . ": #" . $id;
  }
}


if (!function_exists('csrf_field')) {
  function csrf_field(): string {
    return '<input type="hidden" name="_csrf" value="' . e(csrf_token()) . '">';
  }
}

// =====================
// Import helpers (CSV/XLSX)
// =====================
if (!function_exists('valid_emirates_id')) {
  function valid_emirates_id($s): bool {
    $s = trim((string)$s);
    return (bool)preg_match('/^\d{15}$/', $s);
  }
}

if (!function_exists('norm_float')) {
  function norm_float($v) {
    if ($v === null) return null;
    $v = trim((string)$v);
    if ($v === '') return null;
    $v = str_replace([',',' '], ['.',''], $v);
    return is_numeric($v) ? (float)$v : null;
  }
}

if (!function_exists('spreadsheet_rows')) {
  /**
   * Read CSV or XLSX (first sheet) into array of rows (arrays of strings).
   * Designed for preview/import screens without external libraries.
   */
  function spreadsheet_rows(string $path, int $maxRows = 2000): array {
    $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
    if ($ext === 'csv') {
      $rows = [];
      if (($h = fopen($path, 'r')) !== false) {
        // Try to handle UTF-8 BOM
        $first = true;
        while (($r = fgetcsv($h)) !== false) {
          if ($first && isset($r[0])) {
            $r[0] = preg_replace('/^\xEF\xBB\xBF/', '', $r[0]);
            $first = false;
          }
          $rows[] = array_map(fn($x) => is_string($x) ? trim($x) : (string)$x, $r);
          if (count($rows) >= $maxRows) break;
        }
        fclose($h);
      }
      return $rows;
    }
    if ($ext === 'xlsx') {
      return xlsx_rows($path, $maxRows);
    }
    return [];
  }
}

if (!function_exists('xlsx_rows')) {
  /**
   * Minimal XLSX reader (first worksheet). Supports shared strings.
   * This is NOT a full Excel engine, but works for simple tabular sheets.
   */
  function xlsx_rows(string $path, int $maxRows = 2000): array {
    if (!class_exists('ZipArchive')) return [];
    $zip = new ZipArchive();
    if ($zip->open($path) !== true) return [];

    $shared = [];
    $sharedXml = $zip->getFromName('xl/sharedStrings.xml');
    if ($sharedXml) {
      $sx = @simplexml_load_string($sharedXml);
      if ($sx) {
        foreach ($sx->si as $si) {
          // Some strings are split in <r><t>
          if (isset($si->t)) {
            $shared[] = (string)$si->t;
          } else {
            $txt = '';
            foreach ($si->r as $r) { $txt .= (string)$r->t; }
            $shared[] = $txt;
          }
        }
      }
    }

    // Prefer sheet1, else first worksheet found
    $sheetName = 'xl/worksheets/sheet1.xml';
    if ($zip->locateName($sheetName) === false) {
      // Find first worksheet
      for ($i=0; $i<$zip->numFiles; $i++) {
        $n = $zip->getNameIndex($i);
        if (preg_match('#^xl/worksheets/sheet\d+\.xml$#', $n)) { $sheetName = $n; break; }
      }
    }

    $sheetXml = $zip->getFromName($sheetName);
    $zip->close();
    if (!$sheetXml) return [];

    $sx = @simplexml_load_string($sheetXml);
    if (!$sx || !isset($sx->sheetData)) return [];

    $rows = [];
    foreach ($sx->sheetData->row as $row) {
      $out = [];
      foreach ($row->c as $c) {
        $t = (string)($c['t'] ?? '');
        $v = '';
        if ($t === 's') {
          $idx = (int)$c->v;
          $v = $shared[$idx] ?? '';
        } elseif ($t === 'inlineStr') {
          $v = (string)($c->is->t ?? '');
        } else {
          $v = (string)($c->v ?? '');
        }
        $out[] = trim($v);
      }
      $rows[] = $out;
      if (count($rows) >= $maxRows) break;
    }
    return $rows;
  }
}

if (!function_exists('rows_with_headers')) {
  /** Convert first row to headers and build list of associative rows */
  function rows_with_headers(array $rows): array {
    if (count($rows) < 2) return ['headers'=>[], 'rows'=>[]];
    $headers = array_map(function($h){
      $h = trim((string)$h);
      $h = strtolower($h);
      $h = str_replace([' ', '-', '\t'], '_', $h);
      return $h;
    }, $rows[0]);
    $out = [];
    for ($i=1; $i<count($rows); $i++) {
      $r = [];
      foreach ($headers as $j=>$h) {
        if ($h === '') continue;
        $r[$h] = $rows[$i][$j] ?? '';
      }
      // Skip empty rows
      $allEmpty = true;
      foreach ($r as $v) { if (trim((string)$v) !== '') { $allEmpty = false; break; } }
      if (!$allEmpty) $out[] = $r;
    }
    return ['headers'=>$headers, 'rows'=>$out];
  }
}
