<?php
/**
 * approval-action.php
 * Handler kelulusan/penolakan untuk Admin / EXCO (Pencadang) / EXCO (Penyokong)
 * - Auto-detect stage jika tidak dibekalkan
 * - Enforce akses:
 *      * stage=exco         → ikut lantikan district (district_role_assignment.role='exco')
 *      * stage=ajk (support)→ assigned_ajk_id = user_id (EXCO penyokong) — tidak ikut district
 * - Transaksi untuk operasi pindah data
 * - Log ke approval_logs (termasuk district_id)
 */

session_start();
ini_set('display_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/db.php';

// ===== Auth =====
if (!isset($_SESSION['user'])) { header('Location: login.php'); exit; }
$userId     = (int)($_SESSION['user']['id'] ?? 0);
$userRole   = $_SESSION['user']['role'] ?? ''; // admin|exco|ajk (ajk = legacy, sebagai penyokong)
$viewerName = $_SESSION['user']['name'] ?? ($_SESSION['user']['full_name'] ?? '');

if ($userId <= 0 || !in_array($userRole, ['admin','exco','ajk'], true)) {
  echo "<script>alert('Unauthorized.'); window.location.href='login.php';</script>"; exit;
}

// ===== Inputs =====
$id       = isset($_POST['id']) ? (int)$_POST['id'] : 0;
$stage    = isset($_POST['stage']) ? strtolower(trim($_POST['stage'])) : ''; // exco|ajk (ajk = EXCO Penyokong)
$action   = isset($_POST['action']) ? strtolower(trim($_POST['action'])) : ''; // approve|reject
$reasonId = isset($_POST['reason_id']) ? (int)$_POST['reason_id'] : 0;

// ===== Helpers =====
function notifyAndRedirect($message, $to='dashboard.php'){
  echo "<script>alert('".addslashes($message)."'); window.location.href='".addslashes($to)."';</script>";
  exit;
}

function fetchScalar(mysqli $conn, string $sql, string $types = '', ...$params) {
  $stmt = $conn->prepare($sql);
  if (!$stmt) { throw new Exception('DB Error (prepare): '.$conn->error); }
  if ($types) { $stmt->bind_param($types, ...$params); }
  if (!$stmt->execute()) { throw new Exception('DB Error (execute): '.$stmt->error); }
  $stmt->bind_result($val);
  $stmt->fetch();
  $stmt->close();
  return $val;
}

function existsIn(mysqli $conn, string $table, int $id): bool {
  $sql = "SELECT 1 FROM {$table} WHERE id=? LIMIT 1";
  $stmt = $conn->prepare($sql);
  if (!$stmt) { throw new Exception('DB Error (prepare exists): '.$conn->error); }
  $stmt->bind_param('i', $id);
  if (!$stmt->execute()) { throw new Exception('DB Error (execute exists): '.$stmt->error); }
  $stmt->store_result();
  $has = $stmt->num_rows > 0;
  $stmt->close();
  return $has;
}

function detectStage(mysqli $conn, int $id): string {
  if (existsIn($conn, 'pending_exco', $id)) return 'exco';
  if (existsIn($conn, 'pending_ajk',  $id)) return 'ajk'; // ajk = EXCO (Penyokong)
  return '';
}

function fetchNameFrom(mysqli $conn, string $table, int $id): string {
  return (string) fetchScalar($conn, "SELECT full_name FROM {$table} WHERE id = ? LIMIT 1", 'i', $id);
}

function fetchDistrictId(mysqli $conn, string $table, int $id): int {
  return (int) fetchScalar($conn, "SELECT district_id FROM {$table} WHERE id = ? LIMIT 1", 'i', $id);
}
function fetchReasonText(mysqli $conn, int $reasonId): string {
  if ($reasonId <= 0) return '';
  $txt = (string) fetchScalar($conn, "SELECT reason FROM rejection_reasons WHERE id=? AND active=1", 'i', $reasonId);
  return trim($txt);
}

// Semak lantikan district untuk EXCO Pencadang
function userHasDistrictAccess(mysqli $conn, int $userId, string $role, int $districtId): bool {
  $sql = "SELECT 1 FROM district_role_assignment WHERE member_id=? AND role=? AND is_active=1 AND district_id=? LIMIT 1";
  $stmt = $conn->prepare($sql);
  if (!$stmt) { throw new Exception('DB Error (prepare access): '.$conn->error); }
  $stmt->bind_param('isi', $userId, $role, $districtId);
  if (!$stmt->execute()) { throw new Exception('DB Error (execute access): '.$stmt->error); }
  $stmt->store_result();
  $ok = $stmt->num_rows > 0;
  $stmt->close();
  return $ok;
}

// Semak tugasan EXCO (Penyokong) untuk pending_ajk
function userIsAssignedSupporter(mysqli $conn, int $userId, int $pendingAjkId): bool {
  $sql = "SELECT 1 FROM pending_ajk WHERE id=? AND assigned_ajk_id=? LIMIT 1";
  $stmt = $conn->prepare($sql);
  if (!$stmt) { throw new Exception('DB Error (prepare supporter): '.$conn->error); }
  $stmt->bind_param('ii', $pendingAjkId, $userId);
  if (!$stmt->execute()) { throw new Exception('DB Error (execute supporter): '.$stmt->error); }
  $stmt->store_result();
  $ok = $stmt->num_rows > 0;
  $stmt->close();
  return $ok;
}

function logAction(mysqli $conn, int $memberId, string $memberName, int $districtId, int $approvedBy, string $approverRole, string $actionType, ?string $reason = null){
  $sql = "INSERT INTO approval_logs (member_id, member_name, district_id, approved_by, role, action, rejection_reason)
          VALUES (?, ?, ?, ?, ?, ?, ?)";
  $stmt = $conn->prepare($sql);
  if (!$stmt) { throw new Exception('DB Error (logAction prepare): '.$conn->error); }
  $stmt->bind_param('isiisss', $memberId, $memberName, $districtId, $approvedBy, $approverRole, $actionType, $reason);
  if (!$stmt->execute()) { throw new Exception('DB Error (logAction execute): '.$stmt->error); }
  $stmt->close();
}

function txBegin(mysqli $conn){ if(!$conn->begin_transaction()) throw new Exception('Failed to start transaction'); }
function txCommit(mysqli $conn){ if(!$conn->commit()) throw new Exception('Failed to commit'); }
function txRollback(mysqli $conn){ $conn->rollback(); }

// ===== Validate basic =====
if ($id <= 0 || !in_array($action, ['approve','reject'], true)) {
  notifyAndRedirect('Invalid request.');
}

// ===== Stage fallback (auto-detect) =====
if ($stage !== 'exco' && $stage !== 'ajk') {
  $stage = detectStage($conn, $id);
}

// ===== Source table =====
$srcTable = ($stage === 'exco') ? 'pending_exco' : (($stage === 'ajk') ? 'pending_ajk' : '');

// Rekod mesti wujud
if ($srcTable === '') {
  // last chance
  $stage = detectStage($conn, $id);
  $srcTable = ($stage === 'exco') ? 'pending_exco' : (($stage === 'ajk') ? 'pending_ajk' : '');
  if ($srcTable === '') notifyAndRedirect('Rekod tidak dijumpai pada mana-mana peringkat (EXCO/EXCO Penyokong).');
}

// ===== Ambil district rekod untuk log/enforcement =====
$recordDistrictId = fetchDistrictId($conn, $srcTable, $id);

// ===== Role-level enforcement =====
if ($userRole !== 'admin') {
  if ($stage === 'exco') {
    // EXCO (Pencadang) → mesti ada lantikan district
    if (!userHasDistrictAccess($conn, $userId, 'exco', $recordDistrictId)) {
      notifyAndRedirect('Anda tidak dibenarkan memproses rekod ini (bukan dalam district lantikan EXCO anda).');
    }
  } else { // stage === 'ajk' → EXCO (Penyokong)
    // EXCO/ajk (legacy) sebagai penyokong → mesti assigned_ajk_id = userId
    if (!userIsAssignedSupporter($conn, $userId, $id)) {
      notifyAndRedirect('Anda bukan EXCO (Penyokong) yang ditetapkan untuk rekod ini.');
    }
  }
}

try {
  txBegin($conn);

  if ($action === 'approve') {

    if ($userRole === 'admin') {
      // Admin: terus pindahkan dari stage semasa → members (kekal district_id)
      $fullName = fetchNameFrom($conn, $srcTable, $id);
      logAction($conn, $id, $fullName, $recordDistrictId, $userId, 'admin', 'approved');

      // Tambah medan assigned_* jika wujud pada source → pilih ikut skema sedia ada
      $sqlInsert = "INSERT INTO members (
          id, full_name, staff_number, ic_number, email,
          job_title, home_phone, phone, race, district_id, location,
          exco_auto, exco_select, password_hash, created_at,
          role, status, exco_approval, ajk_approval,
          address, postcode, receipt, ack_form, ack_date
        ) SELECT
          id, full_name, staff_number, ic_number, email,
          job_title, home_phone, phone, race, district_id, location,
          exco_auto, exco_select, password_hash, created_at,
          'member', 1, 
          COALESCE(exco_approval, 0), COALESCE(ajk_approval, 0),
          address, postcode, receipt, ack_form, ack_date
        FROM {$srcTable} WHERE id = ?";
      $stmt = $conn->prepare($sqlInsert);
      if (!$stmt) throw new Exception('DB Error (insert members by admin): '.$conn->error);
      $stmt->bind_param('i', $id);
      if (!$stmt->execute()) throw new Exception('DB Error (execute insert members by admin): '.$stmt->error);
      $stmt->close();

      $stmt = $conn->prepare("DELETE FROM {$srcTable} WHERE id = ?");
      $stmt->bind_param('i', $id);
      $stmt->execute();
      $stmt->close();

      txCommit($conn);
      notifyAndRedirect('Permohonan telah diluluskan (Admin).');
    }

    if ($stage === 'exco') {
      // EXCO (Pencadang) approve → set exco_approval=1, pindah ke pending_ajk
      $fullName = fetchNameFrom($conn, 'pending_exco', $id);

      $stmt = $conn->prepare("UPDATE pending_exco SET exco_approval = 1 WHERE id = ?");
      $stmt->bind_param('i', $id);
      $stmt->execute();
      $stmt->close();

      logAction($conn, $id, $fullName, $recordDistrictId, $userId, 'exco', 'approved');

      // Kekalkan assigned_exco_id & assigned_ajk_id semasa pindah
      $sqlMove = "INSERT INTO pending_ajk (
          id, full_name, staff_number, ic_number, email,
          job_title, home_phone, phone, race, district_id, location,
          assigned_exco_id, assigned_ajk_id,
          exco_auto, exco_select, password_hash, created_at,
          role, status, exco_approval, ajk_approval,
          address, postcode, receipt, ack_form, ack_date
        ) SELECT
          id, full_name, staff_number, ic_number, email,
          job_title, home_phone, phone, race, district_id, location,
          assigned_exco_id, assigned_ajk_id,
          exco_auto, exco_select, password_hash, created_at,
          'ajk', 0, exco_approval, 0,
          address, postcode, receipt, ack_form, ack_date
        FROM pending_exco WHERE id = ?";
      $stmt = $conn->prepare($sqlMove);
      if (!$stmt) throw new Exception('DB Error (move to pending_ajk): '.$conn->error);
      $stmt->bind_param('i', $id);
      $stmt->execute();
      $stmt->close();

      $stmt = $conn->prepare("DELETE FROM pending_exco WHERE id = ?");
      $stmt->bind_param('i', $id);
      $stmt->execute();
      $stmt->close();

      txCommit($conn);
      notifyAndRedirect('Permohonan diluluskan oleh EXCO (Pencadang) dan dipanjangkan ke EXCO (Penyokong).');
    }

    if ($stage === 'ajk') { // EXCO (Penyokong)
      // Supporter approve → set ajk_approval=1, pindah ke members
      $fullName = fetchNameFrom($conn, 'pending_ajk', $id);

      $stmt = $conn->prepare("UPDATE pending_ajk SET ajk_approval = 1 WHERE id = ?");
      $stmt->bind_param('i', $id);
      $stmt->execute();
      $stmt->close();

      // Log guna nama role yang konsisten dengan ENUM DB
      $roleForLog = ($userRole === 'admin') ? 'admin' : 'exco_supporter';
      logAction($conn, $id, $fullName, $recordDistrictId, $userId, $roleForLog, 'approved');

      $sqlFinal = "INSERT INTO members (
          id, full_name, staff_number, ic_number, email,
          job_title, home_phone, phone, race, district_id, location,
          exco_auto, exco_select, password_hash, created_at,
          role, status, exco_approval, ajk_approval,
          address, postcode, receipt, ack_form, ack_date
        ) SELECT
          id, full_name, staff_number, ic_number, email,
          job_title, home_phone, phone, race, district_id, location,
          exco_auto, exco_select, password_hash, created_at,
          'member', 1, COALESCE(exco_approval,0), COALESCE(ajk_approval,1),
          address, postcode, receipt, ack_form, ack_date
        FROM pending_ajk WHERE id = ?";
      $stmt = $conn->prepare($sqlFinal);
      if (!$stmt) throw new Exception('DB Error (insert members final): '.$conn->error);
      $stmt->bind_param('i', $id);
      $stmt->execute();
      $stmt->close();

      $stmt = $conn->prepare("DELETE FROM pending_ajk WHERE id = ?");
      $stmt->bind_param('i', $id);
      $stmt->execute();
      $stmt->close();

      txCommit($conn);
      notifyAndRedirect('Permohonan telah diluluskan oleh EXCO (Penyokong).');
    }

    // Fallback
    txCommit($conn);
    notifyAndRedirect('Operasi selesai.');
  }

  // ===== REJECT =====
  if ($action === 'reject') {
    // reason_id wajib & valid
    if ($reasonId <= 0) throw new Exception('Sila pilih alasan penolakan.');
    $reasonText = fetchReasonText($conn, $reasonId);
    if ($reasonText === '') throw new Exception('Alasan penolakan tidak sah atau tidak aktif.');

    // Ambil info asas untuk log
    $fullName   = fetchNameFrom($conn, $srcTable, $id);
    $roleForLog = ($userRole === 'admin') ? 'admin' : ($stage === 'ajk' ? 'exco_supporter' : 'exco');

    logAction($conn, $id, $fullName, $recordDistrictId, $userId, $roleForLog, 'rejected', $reasonText);

    // Simpan ke rejected_user (schema lama kekal)
    $sqlReject = "INSERT INTO rejected_user (
        id, full_name, staff_number, ic_number, email,
        job_title, home_phone, phone, race, location,
        rejection_reason, created_at
      ) SELECT
        id, full_name, staff_number, ic_number, email,
        job_title, home_phone, phone, race, location,
        ?, NOW()
      FROM {$srcTable} WHERE id = ?";
    $stmt = $conn->prepare($sqlReject);
    if (!$stmt) throw new Exception('DB Error (insert rejected_user): '.$conn->error);
    $stmt->bind_param('si', $reasonText, $id);
    $stmt->execute();
    $stmt->close();

    // Padam dari source
    $stmt = $conn->prepare("DELETE FROM {$srcTable} WHERE id = ?");
    $stmt->bind_param('i', $id);
    $stmt->execute();
    $stmt->close();

    txCommit($conn);
    $by = ($userRole === 'admin') ? 'Admin' : ($stage === 'ajk' ? 'EXCO (Penyokong)' : 'EXCO');
    notifyAndRedirect("Permohonan telah ditolak oleh {$by}.");
  }

} catch (Throwable $e) {
  txRollback($conn);
  notifyAndRedirect('Ralat: '.$e->getMessage());
}
