<?php
/**
 * user-edit.php — Admin-only
 * District ↔ Work Location (AJAX linkage)
 * - Work Location list filters by selected District (AJAX)
 * - Jika Work Location ditukar, District auto-switch ke parent (AJAX)
 * EXCO auto by district & enforce 1 EXCO aktif per district (jika kolum/tabl wujud)
 * AJK dropdown = ALL AJK (global), tidak ikut district
 */

session_start();
require_once __DIR__ . "/db.php";

/* ========== Auth: admin only ========== */
if (!isset($_SESSION['user']) || (($_SESSION['user']['role'] ?? '') !== 'admin')) {
    header("Location: dashboard.php"); exit;
}

/* ===== Helpers asas ===== */
function table_exists(mysqli $conn, string $table): bool {
    $sql = "SELECT COUNT(*) AS c
              FROM INFORMATION_SCHEMA.TABLES
             WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?";
    $stmt = $conn->prepare($sql);
    if (!$stmt) return false;
    $stmt->bind_param('s', $table);
    $stmt->execute();
    $res = $stmt->get_result()->fetch_assoc();
    $stmt->close();
    return ((int)($res['c'] ?? 0)) > 0;
}
function column_exists(mysqli $conn, string $table, string $column): bool {
    $sql = "SELECT COUNT(*) AS c
              FROM INFORMATION_SCHEMA.COLUMNS
             WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND COLUMN_NAME = ?";
    $stmt = $conn->prepare($sql);
    if (!$stmt) return false;
    $stmt->bind_param('ss', $table, $column);
    $stmt->execute();
    $res = $stmt->get_result()->fetch_assoc();
    $stmt->close();
    return ((int)($res['c'] ?? 0)) > 0;
}
function active_col(mysqli $conn, string $table): ?string {
    if (!table_exists($conn,$table)) return null;
    if (column_exists($conn,$table,'is_active')) return 'is_active';
    if (column_exists($conn,$table,'active'))    return 'active';
    return null;
}

/* ===== AJAX endpoints (admin session required) =====
   - ?ajax=work_locations&district_id=#
   - ?ajax=district_by_workloc&work_location_id=#
   - ?ajax=exco_name&district_id=#
*/
if (isset($_GET['ajax'])) {
    header('Content-Type: application/json; charset=utf-8');
    $out = ['ok'=>false,'data'=>null,'error'=>null];

    $what = trim((string)$_GET['ajax']);
    if ($what === 'work_locations') {
        $did = (int)($_GET['district_id'] ?? 0);
        if ($did <= 0) { echo json_encode(['ok'=>true,'data'=>[]]); exit; }
        if (!table_exists($conn,'work_locations')) { echo json_encode(['ok'=>true,'data'=>[]]); exit; }

        $acol = active_col($conn,'work_locations');
        $cond = $acol ? " AND COALESCE($acol,1)=1" : "";
        $stmt = $conn->prepare("SELECT id, name FROM work_locations WHERE district_id=? $cond ORDER BY name ASC");
        if ($stmt) {
            $stmt->bind_param('i',$did);
            $stmt->execute();
            $rows = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
            $stmt->close();
            $out = ['ok'=>true,'data'=>$rows];
        } else {
            $out['error'] = 'Server error.';
        }
        echo json_encode($out); exit;
    }

    if ($what === 'district_by_workloc') {
        $wlId = (int)($_GET['work_location_id'] ?? 0);
        if ($wlId <= 0 || !table_exists($conn,'work_locations')) { echo json_encode(['ok'=>true,'data'=>['district_id'=>0]]); exit; }
        $stmt = $conn->prepare("SELECT district_id FROM work_locations WHERE id=? LIMIT 1");
        if ($stmt) {
            $stmt->bind_param('i',$wlId);
            $stmt->execute();
            $did = (int)($stmt->get_result()->fetch_assoc()['district_id'] ?? 0);
            $stmt->close();
            echo json_encode(['ok'=>true,'data'=>['district_id'=>$did]]); exit;
        }
        echo json_encode(['ok'=>false,'error'=>'Server error.']); exit;
    }

    if ($what === 'exco_name') {
        // optional, untuk update paparan EXCO auto di UI
        $did = (int)($_GET['district_id'] ?? 0);
        $name = '';
        if ($did > 0 && column_exists($conn,'members','role') && column_exists($conn,'members','district_id') && column_exists($conn,'members','status')) {
            $stmt = $conn->prepare("SELECT full_name FROM members WHERE role='exco' AND COALESCE(status,1)=1 AND district_id=? LIMIT 1");
            if ($stmt) {
                $stmt->bind_param('i',$did);
                $stmt->execute();
                $name = (string)($stmt->get_result()->fetch_assoc()['full_name'] ?? '');
                $stmt->close();
            }
        }
        echo json_encode(['ok'=>true,'data'=>['name'=>$name]]); exit;
    }

    echo json_encode(['ok'=>false,'error'=>'Unknown ajax action']); exit;
}

/* ========== Get & validate ID ========== */
if (!isset($_GET['id'])) { echo "User ID not specified."; exit; }
$id = (int) $_GET['id']; if ($id <= 0) { echo "Invalid user ID."; exit; }

/* ========== CSRF ========== */
if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); }
function check_csrf() {
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        $token = $_POST['csrf_token'] ?? '';
        if (!hash_equals($_SESSION['csrf_token'] ?? '', $token)) {
            http_response_code(400); die('Invalid CSRF token.');
        }
    }
}

/* ========== Helpers lain ========== */
function starts_with_slash($s) { return isset($s[0]) && $s[0] === '/'; }
function is_abs_url($s) { return (bool)preg_match('~^https?://~i', (string)$s); }
function status_label($v): string { return ((int)$v === 1) ? 'Active' : 'Inactive'; }
function fmtDT($v, $fmt) {
    if ($v === null) return '-';
    $s = trim((string)$v);
    if ($s === '' || $s === '0000-00-00' || $s === '0000-00-00 00:00:00') return '-';
    $ts = strtotime($s);
    if ($ts === false || $ts <= 0) return '-';
    return date($fmt, $ts);
}
function write_audit(mysqli $conn, int $adminId, int $memberId, string $action) {
    if (!table_exists($conn,'audit_logs')) return;
    $stmt = $conn->prepare("INSERT INTO audit_logs (admin_id, member_id, action) VALUES (?, ?, ?)");
    if ($stmt) {
        $stmt->bind_param("iis", $adminId, $memberId, $action);
        $stmt->execute(); $stmt->close();
    }
}

/* ========== Lookups & business helpers ========== */
function fetch_member(mysqli $conn, int $id): array {
    $hasDistrictId   = column_exists($conn,'members','district_id');
    $hasWorklocId    = column_exists($conn,'members','work_location_id');
    $hasLocationStr  = column_exists($conn,'members','location');
    $hasDistrictsTbl = table_exists($conn,'districts');
    $hasWorklocsTbl  = table_exists($conn,'work_locations');

    $cols = [
        "m.id","m.full_name","m.staff_number","m.ic_number","m.email","m.phone",
        (column_exists($conn,'members','race') ? "m.race" : "NULL AS race"),
        $hasLocationStr ? "m.location" : "NULL AS location",
        $hasDistrictId ? "m.district_id" : "NULL AS district_id",
        $hasWorklocId ? "m.work_location_id" : "NULL AS work_location_id",
        (column_exists($conn,'members','exco_auto')   ? "m.exco_auto"   : "NULL AS exco_auto"),
        (column_exists($conn,'members','exco_select') ? "m.exco_select" : "NULL AS exco_select"),
        (column_exists($conn,'members','role')        ? "m.role"        : "NULL AS role"),
        (column_exists($conn,'members','waris_name')  ? "m.waris_name"  : "NULL AS waris_name"),
        (column_exists($conn,'members','waris_phone') ? "m.waris_phone" : "NULL AS waris_phone"),
        (column_exists($conn,'members','status') ? "COALESCE(m.status,0)" : "0")." AS status",
        (column_exists($conn,'members','deactivated_reason_id') ? "m.deactivated_reason_id" : "NULL AS deactivated_reason_id"),
        (column_exists($conn,'members','deactivated_at') ? "m.deactivated_at" : "NULL AS deactivated_at"),
        (column_exists($conn,'members','deactivated_by') ? "m.deactivated_by" : "NULL AS deactivated_by"),
    ];
    $joins = [];
    if ($hasDistrictsTbl && $hasDistrictId) {
        $joins[] = "LEFT JOIN districts d ON d.id = m.district_id";
        $cols[]  = "d.name AS district_name";
    } else {
        $cols[] = "NULL AS district_name";
    }
    if ($hasWorklocsTbl && $hasWorklocId) {
        $joins[] = "LEFT JOIN work_locations wl ON wl.id = m.work_location_id";
        $cols[]  = "wl.name AS work_location_name";
    } else {
        $cols[] = "NULL AS work_location_name";
    }

    $sql = "SELECT ".implode(", ", $cols)." FROM members m ".implode(" ", $joins)." WHERE m.id=? LIMIT 1";
    $stmt = $conn->prepare($sql);
    if (!$stmt) { die("User not found."); }
    $stmt->bind_param("i",$id);
    $stmt->execute();
    $res = $stmt->get_result();
    $row = $res->fetch_assoc();
    $stmt->close();

    if (!$row) { die("User not found."); }
    foreach (['district_id','district_name','work_location_id','work_location_name','location'] as $k) {
        if (!array_key_exists($k, $row)) $row[$k] = null;
    }
    return $row;
}

function fetch_member_dates(mysqli $conn, int $memberId): array {
    $hasApp      = column_exists($conn,'members','application_date');
    $hasExco     = column_exists($conn,'members','exco_approved_at');
    $hasAjk      = column_exists($conn,'members','ajk_approved_at');
    $hasOfficial = column_exists($conn,'members','official_member_since');
    $hasCreated  = column_exists($conn,'members','created_at');

    $parts = [];
    $parts[] = $hasApp      ? "application_date"      : "NULL AS application_date";
    $parts[] = $hasExco     ? "exco_approved_at"      : "NULL AS exco_approved_at";
    $parts[] = $hasAjk      ? "ajk_approved_at"       : "NULL AS ajk_approved_at";
    $parts[] = "NULL AS admin_approved_at";
    $parts[] = $hasOfficial ? "official_member_since" : "NULL AS official_member_since";
    $parts[] = $hasCreated  ? "created_at"            : "NULL AS created_at";
    $select = implode(", ", $parts);

    $row = ['application_date'=>null,'exco_approved_at'=>null,'ajk_approved_at'=>null,'admin_approved_at'=>null,'official_member_since'=>null,'created_at'=>null];

    $stmt = $conn->prepare("SELECT $select FROM members WHERE id=? LIMIT 1");
    if ($stmt) {
        $stmt->bind_param('i',$memberId);
        if ($stmt->execute()) {
            $r = $stmt->get_result()->fetch_assoc();
            if ($r) { $row = array_merge($row,$r); }
        }
        $stmt->close();
    }

    if (empty($row['application_date']) && !empty($row['created_at'])) $row['application_date'] = $row['created_at'];

    // approval_logs (optional)
    $pullFirst = function(string $role) use ($conn,$memberId){
        if (!table_exists($conn,'approval_logs')) return null;
        $sql="SELECT `timestamp` FROM approval_logs WHERE member_id=? AND role=? AND action='approved' ORDER BY `timestamp` ASC LIMIT 1";
        $st=$conn->prepare($sql); if(!$st) return null;
        $st->bind_param('is',$memberId,$role); $st->execute();
        $val = ($st->get_result()->fetch_assoc()['timestamp'] ?? null);
        $st->close(); return $val;
    };
    if (empty($row['exco_approved_at'])) $row['exco_approved_at'] = $pullFirst('exco');
    if (empty($row['ajk_approved_at']))  $row['ajk_approved_at']  = $pullFirst('ajk');
    $row['admin_approved_at'] = $pullFirst('admin');

    if (empty($row['official_member_since'])) {
        $cands = [];
        foreach (['ajk_approved_at','admin_approved_at'] as $k) {
            if (!empty($row[$k])) { $ts = strtotime($row[$k]); if ($ts && $ts>0) $cands[] = $ts; }
        }
        if ($cands) $row['official_member_since'] = date('Y-m-d', min($cands));
    }
    return $row;
}

function fetch_registration_receipt(mysqli $conn, int $memberId): array {
    $out = ['url'=>null,'filename'=>null,'mime'=>null];
    if (!column_exists($conn,'members','receipt')) return $out;
    $stmt = $conn->prepare("SELECT receipt FROM members WHERE id=? LIMIT 1");
    if ($stmt) {
        $stmt->bind_param('i',$memberId);
        if ($stmt->execute()) {
            $r = $stmt->get_result()->fetch_assoc();
            $path = trim((string)($r['receipt'] ?? ''));
            if ($path !== '') {
                $display = (is_abs_url($path) || starts_with_slash($path)) ? $path : $path;
                $out['url'] = $display;
                $out['filename'] = basename($display);
                $ext = strtolower(pathinfo($display, PATHINFO_EXTENSION));
                if (in_array($ext,['jpg','jpeg','png','gif','webp'])) {
                    $out['mime'] = 'image/'.($ext === 'jpg' ? 'jpeg' : $ext);
                } elseif ($ext === 'pdf') {
                    $out['mime'] = 'application/pdf';
                } else {
                    $out['mime'] = 'application/octet-stream';
                }
            }
        }
        $stmt->close();
    }
    return $out;
}

function get_districts(mysqli $conn): array {
    if (!table_exists($conn,'districts')) return [];
    $out=[]; $col = active_col($conn,'districts');
    $q="SELECT id, name FROM districts";
    if ($col) $q.=" WHERE COALESCE($col,1)=1";
    $q.=" ORDER BY name ASC";
    if ($rs=$conn->query($q)) while($r=$rs->fetch_assoc()) $out[]=$r; return $out;
}

/** ====== AJK helpers: ALL AJK (global) ====== */
function get_ajk_list_all(mysqli $conn): array {
    if (!column_exists($conn,'members','role')) return [];
    $list=[];
    $sql="SELECT full_name FROM members WHERE role='ajk' AND COALESCE(status,1)=1 ORDER BY full_name ASC";
    $st=$conn->prepare($sql);
    if ($st) {
        $st->execute(); $res=$st->get_result();
        while($r=$res->fetch_assoc()) $list[]=$r['full_name'];
        $st->close();
    }
    return $list;
}

function email_exists_other(mysqli $conn, string $email, int $excludeId): bool {
    $stmt=$conn->prepare("SELECT id FROM members WHERE email = ? AND id <> ? LIMIT 1");
    if (!$stmt) return false;
    $stmt->bind_param("si",$email,$excludeId); $stmt->execute();
    $res=$stmt->get_result(); $found=$res && $res->num_rows>0; $stmt->close(); return $found;
}

/** ====== EXCO helpers ====== */
function existing_exco_in_district(mysqli $conn, int $districtId, int $excludeId = 0): ?array {
    if ($districtId<=0) return null;
    if (!column_exists($conn,'members','role') || !column_exists($conn,'members','district_id') || !column_exists($conn,'members','status')) return null;
    $sql="SELECT id, full_name FROM members
          WHERE role='exco' AND COALESCE(status,1)=1 AND district_id=? AND id<>? LIMIT 1";
    $st=$conn->prepare($sql); if(!$st) return null;
    $st->bind_param('ii',$districtId,$excludeId); $st->execute();
    $row=$st->get_result()->fetch_assoc(); $st->close(); return $row ?: null;
}
function exco_name_for_district(mysqli $conn, int $districtId): string {
    if ($districtId<=0) return '';
    if (!column_exists($conn,'members','role') || !column_exists($conn,'members','district_id') || !column_exists($conn,'members','status')) return '';
    $sql="SELECT full_name FROM members WHERE role='exco' AND COALESCE(status,1)=1 AND district_id=? LIMIT 1";
    $st=$conn->prepare($sql); if(!$st) return '';
    $st->bind_param('i',$districtId); $st->execute();
    $val = $st->get_result()->fetch_assoc()['full_name'] ?? '';
    $st->close();
    return (string)$val;
}

/* ========== Load current user & lookups ========== */
$user  = fetch_member($conn, $id);
$dates = fetch_member_dates($conn, $id);
$rcpt  = fetch_registration_receipt($conn, $id);

$selectedDistrictId   = (int)($user['district_id'] ?? 0);
$selectedWorklocId    = (int)($user['work_location_id'] ?? 0);

$districts     = get_districts($conn);
$hasWorklocTbl = table_exists($conn,'work_locations');
$useFlatLoc    = !$hasWorklocTbl && table_exists($conn,'locations');

/* Flat locations (fallback) */
function get_locations_flat(mysqli $conn, string $current = ''): array {
    if (!table_exists($conn,'locations')) return [];
    $col = active_col($conn,'locations');
    $q = "SELECT name FROM locations";
    if ($col) $q .= " WHERE COALESCE($col,1)=1";
    $q .= " ORDER BY name ASC";
    $list = [];
    if ($rs = $conn->query($q)) {
        while ($r = $rs->fetch_assoc()) $list[] = $r['name'];
    }
    if ($current !== '' && !in_array($current, $list, true)) array_unshift($list, $current);
    return $list;
}
$flatLocations = $useFlatLoc ? get_locations_flat($conn, (string)($user['location'] ?? '')) : [];

/* AJK list (GLOBAL) */
$ajk_all = get_ajk_list_all($conn);

/* Deactivation reasons */
function get_active_deact_reasons(mysqli $conn): array {
    if (!table_exists($conn,'deactivate_reasons')) return [];
    $out=[]; $res=$conn->query("SELECT id, reason_text FROM deactivate_reasons WHERE active=1 ORDER BY sort_order ASC, reason_text ASC");
    if ($res) while($r=$res->fetch_assoc()) $out[]=$r; return $out;
}
$deactReasons  = get_active_deact_reasons($conn);

/* Flash */
$flash_success = isset($_GET['success']) ? trim($_GET['success']) : '';
$flash_error   = isset($_GET['error'])   ? trim($_GET['error'])   : '';

/* ========== DELETE ========== */
if ($_SERVER['REQUEST_METHOD']==='POST' && isset($_POST['delete_member'])) {
    check_csrf();
    $del=$conn->prepare("DELETE FROM members WHERE id=?");
    if ($del) {
        $del->bind_param("i",$id);
        if ($del->execute()) {
            $adminId=(int)$_SESSION['user']['id'];
            write_audit($conn,$adminId,$id,"Deleted member");
            header("Location: user-management.php?success=".urlencode("Member deleted.")); exit;
        } else { http_response_code(500); echo "Failed to delete."; }
        $del->close(); exit;
    } else {
        http_response_code(500); echo "Server error."; exit;
    }
}

/* ========== UPDATE (district-based) ========== */
if ($_SERVER['REQUEST_METHOD']==='POST' && !isset($_POST['delete_member'])) {
    check_csrf();

    $full_name   = trim($_POST['full_name'] ?? '');
    $email       = strtolower(trim($_POST['email'] ?? ''));
    $phone       = trim($_POST['phone'] ?? '');
    $race        = trim($_POST['race'] ?? '');
    $role        = trim($_POST['role'] ?? '');
    $waris_name  = trim($_POST['waris_name'] ?? '');
    $waris_phone = trim($_POST['waris_phone'] ?? '');
    $status_in   = $_POST['status'] ?? '0';
    $status      = (int)($status_in==='1' ? 1 : 0);

    // Dari form (akan di-override oleh derive)
    $district_id      = (int)($_POST['district_id'] ?? 0);
    $work_location_id = (int)($_POST['work_location_id'] ?? 0);
    $exco_select      = trim($_POST['exco_select'] ?? '');

    if ($full_name==='') die("Full name is required.");
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) die("Invalid email format.");
    if (email_exists_other($conn,$email,$id)) die("Email already used by another member.");
    if ($phone==='') die("Phone is required.");
    if ($waris_phone!=='' && !preg_match('/^[0-9+\-\s]{7,20}$/',$waris_phone)) {
        die("Invalid guardian phone format. Use digits/space/+/- (7–20 chars).");
    }
    $allowedRoles=['admin','exco','ajk','member'];
    if (column_exists($conn,'members','role') && !in_array($role,$allowedRoles,true)) {
        die("Invalid role.");
    }

    /* ====== AUTO-DERIVE district_id ====== */
    $derivedDistrictId = 0;
    $hasDistrictCol = column_exists($conn,'members','district_id');

    if ($hasWorklocTbl && $work_location_id > 0 && $hasDistrictCol) {
        $st = $conn->prepare("SELECT district_id FROM work_locations WHERE id=? LIMIT 1");
        if ($st) {
            $st->bind_param('i', $work_location_id);
            $st->execute();
            $derivedDistrictId = (int)($st->get_result()->fetch_assoc()['district_id'] ?? 0);
            $st->close();
        }
    } elseif ($useFlatLoc && $hasDistrictCol) {
        $loc_in = trim($_POST['location'] ?? '');
        if ($loc_in !== '') {
            $st = $conn->prepare("SELECT district_id FROM locations WHERE name=? LIMIT 1");
            if ($st) {
                $st->bind_param('s', $loc_in);
                $st->execute();
                $derivedDistrictId = (int)($st->get_result()->fetch_assoc()['district_id'] ?? 0);
                $st->close();
            }
        }
    }

    if ($derivedDistrictId > 0) {
        $district_id = $derivedDistrictId;
    } else {
        $district_id = $hasDistrictCol ? (int)($user['district_id'] ?? 0) : 0;
    }

    if ($hasDistrictCol && $district_id <= 0) {
        $ret = "user-edit.php?id={$id}&error=" . urlencode("Please select a valid Work Location (District auto).");
        header("Location: ".$ret); exit;
    }

    // Validasi WL belongs to District
    if ($hasWorklocTbl && $work_location_id > 0 && $hasDistrictCol) {
        $acol = active_col($conn,'work_locations');
        $cond = $acol ? " AND COALESCE($acol,1)=1" : "";
        $sqlC = "SELECT 1 FROM work_locations WHERE id=? AND district_id=? $cond LIMIT 1";
        $chk  = $conn->prepare($sqlC);
        if ($chk) {
            $chk->bind_param('ii',$work_location_id,$district_id);
            $chk->execute(); $chk->store_result();
            if ($chk->num_rows === 0) {
                if (!($work_location_id === (int)($user['work_location_id'] ?? 0) && $district_id === (int)($user['district_id'] ?? 0))) {
                    $chk->close();
                    $ret = "user-edit.php?id={$id}&error=" . urlencode("Selected Work Location does not belong to the derived District (or is inactive).");
                    header("Location: ".$ret); exit;
                }
            }
            $chk->close();
        }
    }

    // EXCO uniqueness
    if ($role === 'exco' && $status === 1) {
        $conflict = existing_exco_in_district($conn, $district_id, $id);
        if ($conflict) {
            $err = "District already has an active EXCO: " . ($conflict['full_name'] ?? '—') . ".";
            $ret = "user-edit.php?id={$id}&error=" . urlencode($err);
            header("Location: ".$ret); exit;
        }
    }

    // Deactivate reason
    $hasDeactReasonCol = column_exists($conn,'members','deactivated_reason_id');
    $hasDeactAtCol     = column_exists($conn,'members','deactivated_at');
    $hasDeactByCol     = column_exists($conn,'members','deactivated_by');
    $deact_reason_id = null;

    if ($status === 0 && $hasDeactReasonCol) {
        $deact_reason_id = isset($_POST['deactivated_reason_id']) ? (int)$_POST['deactivated_reason_id'] : 0;
        if ($deact_reason_id <= 0) {
            $ret = "user-edit.php?id={$id}&error=" . urlencode("Please select a deactivate reason.");
            header("Location: ".$ret); exit;
        }
        if (table_exists($conn,'deactivate_reasons')) {
            $chk=$conn->prepare("SELECT id FROM deactivate_reasons WHERE id=? AND active=1");
            if ($chk) {
                $chk->bind_param("i",$deact_reason_id); $chk->execute();
                $r=$chk->get_result(); if (!$r || $r->num_rows!==1) { $chk->close(); die("Invalid deactivate reason."); }
                $chk->close();
            }
        }
    }

    // EXCO (Auto) recompute ikut district
    $exco_auto = '';
    if (column_exists($conn,'members','exco_auto')) {
        $exco_auto = exco_name_for_district($conn, $district_id);
    }

    // Nama district (untuk fallback location string)
    $district_name = '';
    if (table_exists($conn,'districts') && $hasDistrictCol) {
        $stn = $conn->prepare("SELECT name FROM districts WHERE id=? LIMIT 1");
        if ($stn) {
            $stn->bind_param('i',$district_id); $stn->execute();
            $district_name = (string)($stn->get_result()->fetch_assoc()['name'] ?? ''); $stn->close();
        }
    }

    /* ====== Tentukan string 'location' ====== */
    $location_string = $district_name;
    if ($hasWorklocTbl && $work_location_id > 0) {
        $st_wl = $conn->prepare("SELECT name FROM work_locations WHERE id=? LIMIT 1");
        if ($st_wl) {
            $st_wl->bind_param('i', $work_location_id);
            $st_wl->execute();
            $location_string = (string)($st_wl->get_result()->fetch_assoc()['name'] ?? $district_name);
            $st_wl->close();
        }
    } elseif ($useFlatLoc) {
        $location_string = trim($_POST['location'] ?? $user['location'] ?? $district_name);
    } else {
        if (!column_exists($conn,'members','location')) $location_string = (string)($user['location'] ?? '');
    }

    // Build change summary
    $before = $user;
    $after  = [
        'full_name'=>$full_name,'email'=>$email,'phone'=>$phone,'race'=>$race,
        'district_id'=>$district_id,'work_location_id'=>$work_location_id,
        'location'=>$location_string,
        'exco_auto'=>$exco_auto,'exco_select'=>$exco_select,
        'role'=>$role,'waris_name'=>$waris_name,'waris_phone'=>$waris_phone,'status'=>$status,
        'deactivated_reason_id'=>($status===0?$deact_reason_id:null)
    ];
    $changed=[];
    foreach ($after as $k=>$v) {
        if (!array_key_exists($k, $before)) continue;
        $prev = $before[$k] ?? null;
        if ($k==='status') { if ((int)$prev !== (int)$v) $changed[]="status: '".status_label($prev)."' → '".status_label($v)."'"; }
        else {
            if ((string)$prev !== (string)$v) {
                if ($k==='district_id')          $changed[]="district_id: '{$prev}' → '{$v}'";
                elseif ($k==='work_location_id') $changed[]="work_location_id: '{$prev}' → '{$v}'";
                else $changed[]="$k: '$prev' → '$v'";
            }
        }
    }
    $summary = $changed ? ("Updated fields — ".implode("; ",$changed)) : "No field changes detected";

    $adminId = (int)$_SESSION['user']['id'];

    /* ========= DINAMIK UPDATE: hanya kolum yang wujud ========= */
    $set = []; $types=''; $vals=[];

    foreach ([
        ['full_name','s',$full_name],
        ['email','s',$email],
        ['phone','s',$phone],
    ] as $x) {
        if (column_exists($conn,'members',$x[0])) { $set[] = "{$x[0]}=?"; $types.=$x[1]; $vals[] = $x[2]; }
    }

    if (column_exists($conn,'members','race')) { $set[]="race=?"; $types.='s'; $vals[]=$race; }

    if (column_exists($conn,'members','district_id')) { $set[]="district_id=?"; $types.='i'; $vals[]=$district_id; }
    if (column_exists($conn,'members','work_location_id')) { $set[]="work_location_id=?"; $types.='i'; $vals[]=$work_location_id; }
    if (column_exists($conn,'members','location')) { $set[]="location=?"; $types.='s'; $vals[]=$location_string; }

    if (column_exists($conn,'members','exco_auto'))   { $set[]="exco_auto=?"; $types.='s'; $vals[]=$exco_auto; }
    if (column_exists($conn,'members','exco_select')) { $set[]="exco_select=?"; $types.='s'; $vals[]=$exco_select; }

    if (column_exists($conn,'members','role'))  { $set[]="role=?";  $types.='s'; $vals[]=$role; }
    if (column_exists($conn,'members','waris_name'))  { $set[]="waris_name=?";  $types.='s'; $vals[]=$waris_name; }
    if (column_exists($conn,'members','waris_phone')) { $set[]="waris_phone=?"; $types.='s'; $vals[]=$waris_phone; }

    if (column_exists($conn,'members','status')) { $set[]="status=?"; $types.='i'; $vals[]=$status; }

    if ($status===0) {
        if ($hasDeactReasonCol) { $set[]="deactivated_reason_id=?"; $types.='i'; $vals[]=(int)$deact_reason_id; }
        if ($hasDeactAtCol) { $set[]="deactivated_at=NOW()"; }
        if ($hasDeactByCol) { $set[]="deactivated_by=?"; $types.='i'; $vals[]=$adminId; }
    } else {
        if ($hasDeactReasonCol) $set[]="deactivated_reason_id=NULL";
        if ($hasDeactAtCol)     $set[]="deactivated_at=NULL";
        if ($hasDeactByCol)     $set[]="deactivated_by=NULL";
    }

    if (empty($set)) {
        $ret = "user-edit.php?id={$id}&error=".urlencode("No updatable fields in this environment.");
        header("Location: ".$ret); exit;
    }

    $sql = "UPDATE members SET ".implode(", ", $set)." WHERE id=? LIMIT 1";
    $stmt = $conn->prepare($sql);
    if (!$stmt) { http_response_code(500); echo "Server error."; exit; }

    $types .= 'i';
    $vals[] = $id;

    $bind = [$types];
    foreach ($vals as $k => $v) { $bind[] = &$vals[$k]; }
    call_user_func_array([$stmt,'bind_param'],$bind);

    if ($stmt->execute()) {
        write_audit($conn,$adminId,$id,"Updated member profile. ".$summary);
        $ret = "user-edit.php?id={$id}&success=".urlencode("Updates Successfully Saved.");
        header("Location: ".$ret); exit;
    } else {
        error_log("user-edit UPDATE failed: ".$stmt->error." | SQL=".$sql);
        $ret = "user-edit.php?id={$id}&error=".urlencode("Your Updates Unsuccessfull. Please Try Again.");
        header("Location: ".$ret); exit;
    }
}

/* ========== View ========== */
ob_start();
?>
<style>
  :root{
    --pri:#2563eb; --pri-ink:#1e40af;
    --bd:#e5e7eb; --ink:#0f172a; --muted:#64748b; --bg:#f6f7fb;
    --ok:#10b981; --danger:#ef4444; --warn:#f59e0b;
  }
  *{box-sizing:border-box}
  body{font-family:system-ui,-apple-system,Segoe UI,Roboto;margin:0;background:var(--bg);color:var(--ink)}
  .header{background:var(--pri);color:#fff;padding:18px 0;margin:0 0 16px}
  .header .inner{max-width:1100px;margin:0 auto;padding:0 16px;display:flex;align-items:center;justify-content:space-between}
  .title{margin:0;font-size:clamp(20px,2.2vw,26px)}
  .wrap{max-width:1100px;margin:0 auto;padding:0 16px 24px}
  .badge{display:inline-block;padding:6px 10px;border-radius:999px;font-size:12px;font-weight:700;border:1px solid transparent}
  .badge.active{background:#ecfdf5;color:#065f46;border-color:#a7f3d0}
  .badge.inactive{background:#fef2f2;color:#9f1239;border-color:#fecdd3}
  .btn{padding:10px 14px;border:1px solid var(--bd);border-radius:10px;background:#fff;color:#111827;cursor:pointer;font-weight:700;text-decoration:none;display:inline-block}
  .btn.primary{background:var(--pri);border-color:var(--pri);color:#fff}
  .btn.primary:hover{background:var(--pri-ink)}
  .btn.neutral{background:#f3f4f6}
  .btn.danger{background:var(--danger);border-color:var(--danger);color:#fff}
  .card{background:#fff;border:1px solid rgba(0,0,0,.06);border-radius:16px;box-shadow:0 8px 24px rgba(2,6,23,.08);padding:18px}
  .section-title{margin:0 0 12px;font-size:18px}
  .grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
  .grid .full{grid-column:1 / -1}
  label{display:block;font-weight:600;margin-bottom:6px}
  input[type="text"],input[type="email"],select{width:100%;padding:10px;border:1px solid var(--bd);border-radius:10px;background:#fff}
  input[disabled]{background:#f9fafb;color:#6b7280}
  .row-actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:6px}
  .muted{color:var(--muted)}
  .danger-zone{border:1px dashed #fecaca;background:#fff1f2}
  .pill-note{font-size:12px;color:var(--muted);margin-top:6px}
  .timeline{display:grid;grid-template-columns:1fr 1fr;gap:12px}
  .timeline .item{background:#f9fafb;border:1px solid #eef2f7;border-radius:10px;padding:10px 12px}
  .timeline label{margin-bottom:4px;font-weight:600}
  .flash{position:relative;display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:10px;margin:0 0 14px;border:1px solid transparent;box-shadow:0 2px 8px rgba(2,6,23,.06)}
  .flash strong{font-weight:700}
  .flash.success{ background:#ecfdf5; color:#065f46; border-color:#a7f3d0; }
  .flash.error{ background:#fef2f2; color:#991b1b; border-color:#fecaca; }
  .flash .msg{ flex:1; text-align:center; }
  .flash .close{position:absolute; right:10px; top:8px; line-height:1; border:0; background:transparent; font-size:16px; cursor:pointer; color:inherit; opacity:.7; margin:0;}
  .flash .close:hover{ opacity:1; }
  @media (max-width: 900px){ .grid{grid-template-columns:1fr} .timeline{grid-template-columns:1fr} }
</style>

<div class="header">
  <div class="inner">
    <h2 class="title">Edit Member</h2>
    <a href="user-management.php" class="btn neutral">← Back</a>
  </div>
</div>

<div class="wrap">

  <?php if ($flash_success): ?>
    <div class="flash success" id="flashBox" role="alert" aria-live="polite">
      <div class="msg"><strong>Success:</strong> <span><?= htmlspecialchars($flash_success) ?></span></div>
      <button class="close" aria-label="Close" onclick="this.parentElement.remove()">×</button>
    </div>
  <?php elseif ($flash_error): ?>
    <div class="flash error" id="flashBox" role="alert" aria-live="assertive">
      <div class="msg"><strong>Error:</strong> <span><?= htmlspecialchars($flash_error) ?></span></div>
      <button class="close" aria-label="Close" onclick="this.parentElement.remove()">×</button>
    </div>
  <?php endif; ?>

  <!-- ===== Membership Timeline ===== -->
  <div class="card" style="margin-bottom:14px">
    <h3 class="section-title">Membership Timeline</h3>
    <div class="timeline">
      <div class="item"><label>Tarikh Permohonan</label><div><?= fmtDT($dates['application_date'], 'd/m/Y H:i') ?></div></div>
      <div class="item"><label>Kelulusan EXCO</label><div><?= fmtDT($dates['exco_approved_at'], 'd/m/Y H:i') ?></div></div>
      <div class="item"><label>Kelulusan AJK</label><div><?= fmtDT($dates['ajk_approved_at'], 'd/m/Y H:i') ?></div></div>
      <div class="item"><label>Kelulusan Admin</label><div><?= fmtDT($dates['admin_approved_at'], 'd/m/Y H:i') ?></div></div>
      <div class="item"><label>Ahli Rasmi Sejak</label><div><?= fmtDT($dates['official_member_since'], 'd/m/Y') ?></div></div>
    </div>
    <p class="pill-note" style="margin-top:8px"><em>Nota: “Ahli Rasmi Sejak” ialah tarikh terawal antara kelulusan AJK atau Admin (jika medan rasmi kosong).</em></p>
  </div>

  <!-- ===== Registration Receipt ===== -->
  <div class="card" style="margin-bottom:14px">
    <h3 class="section-title">Registration Receipt</h3>
    <?php $hasReceipt = !empty($rcpt['url']); ?>
    <?php if ($hasReceipt): ?>
      <div>
        <div class="pill-note">File: <b><?= htmlspecialchars($rcpt['filename'] ?? '') ?: '—' ?></b></div>
        <div class="receipt-actions" style="margin-top:8px">
          <a class="btn" href="<?= htmlspecialchars($rcpt['url']) ?>" target="_blank" rel="noopener">View / Download</a>
        </div>
      </div>
    <?php else: ?>
      <div class="pill-note">No receipt found for this member.</div>
    <?php endif; ?>
  </div>

  <!-- ===== Form Utama ===== -->
  <div class="card" style="margin-bottom:14px">
    <div class="muted" style="margin-bottom:8px">
      <?= htmlspecialchars($user['full_name']) ?> ·
      <span class="badge <?= ((int)$user['status']===1?'active':'inactive') ?>"><?= status_label($user['status']) ?></span>
    </div>

    <form method="post" autocomplete="off" id="editForm">
      <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">

      <h3 class="section-title">Member Information</h3>
      <div class="grid">
        <div>
          <label>Full Name</label>
          <input type="text" name="full_name" value="<?= htmlspecialchars($user['full_name']) ?>" required>
        </div>
        <div>
          <label>Staff Number</label>
          <input type="text" value="<?= htmlspecialchars($user['staff_number']) ?>" disabled>
        </div>

        <div>
          <label>IC Number</label>
          <input type="text" value="<?= htmlspecialchars($user['ic_number']) ?>" disabled>
        </div>
        <div>
          <label>Email</label>
          <input type="email" name="email" value="<?= htmlspecialchars($user['email']) ?>" required autocomplete="email">
        </div>

        <div>
          <label>Phone Number</label>
          <input type="text" name="phone" value><?= htmlspecialchars($user['phone']) ?> required inputmode="tel" maxlength="20" data-phonemask="my">
        </div>
        <div>
          <label>Race</label>
          <select name="race" required>
            <?php foreach (['Malay','Chinese','Indian','Bumiputera','Others'] as $r): ?>
              <option value="<?= htmlspecialchars($r) ?>" <?= ($user['race']===$r?'selected':'') ?>><?= htmlspecialchars($r) ?></option>
            <?php endforeach; ?>
          </select>
        </div>

        <!-- District & Work Location -->
        <div>
          <label>Work District</label>
          <select name="district_id" id="district_id" <?= column_exists($conn,'members','district_id')?'required':'' ?>>
            <option value="">— Select District —</option>
            <?php foreach ($districts as $d): ?>
              <option value="<?= (int)$d['id'] ?>" <?= ((int)$d['id']===$selectedDistrictId?'selected':'') ?>>
                <?= htmlspecialchars($d['name']) ?>
              </option>
            <?php endforeach; ?>
          </select>
          <div class="pill-note">Server akan auto-override District ikut Work Location / Location master.</div>
        </div>

        <div>
          <label>Work Location</label>
          <?php if ($hasWorklocTbl): ?>
            <select name="work_location_id" id="work_location_id">
              <option value="">— Optional —</option>
              <?php
                // Preload hanya untuk district semasa (elak list besar)
                if ($selectedDistrictId) {
                    $acol = active_col($conn,'work_locations');
                    $cond = $acol ? " AND COALESCE($acol,1)=1" : "";
                    $st = $conn->prepare("SELECT id, name FROM work_locations WHERE district_id=? $cond ORDER BY name ASC");
                    if ($st) {
                        $st->bind_param('i',$selectedDistrictId);
                        $st->execute();
                        $rs = $st->get_result();
                        while($wl=$rs->fetch_assoc()){
                          $sel = ((int)$wl['id'] === $selectedWorklocId) ? 'selected' : '';
                          echo '<option value="'.(int)$wl['id'].'" '.$sel.'>'.htmlspecialchars($wl['name']).'</option>';
                        }
                        $st->close();
                    }
                }
              ?>
            </select>
            <div class="pill-note">Each district may have multiple work locations.</div>
            <div class="pill-note">List page reads from <code>members.location</code>: <b><?= htmlspecialchars($user['location'] ?: '-') ?></b></div>
          <?php elseif ($useFlatLoc): ?>
            <select name="location" id="location_flat">
              <?php foreach ($flatLocations as $nm): ?>
                <option value="<?= htmlspecialchars($nm) ?>" <?= ((string)$user['location'] === (string)$nm ? 'selected' : '') ?>>
                  <?= htmlspecialchars($nm) ?>
                </option>
              <?php endforeach; ?>
            </select>
            <div class="pill-note">This list comes from <code>locations</code> table (district derived automatically).</div>
          <?php else: ?>
            <input type="text" value="<?= htmlspecialchars($user['location'] ?: '-') ?>" disabled>
            <div class="pill-note">No <code>work_locations</code> / <code>locations</code> table detected. Showing current value from <code>members.location</code>.</div>
          <?php endif; ?>
        </div>

        <div>
          <label>EXCO (Auto)</label>
          <?php $autoExcoDisplay = $selectedDistrictId ? exco_name_for_district($conn, $selectedDistrictId) : ''; ?>
          <input type="text" id="exco_auto_display" value="<?= htmlspecialchars($autoExcoDisplay) ?>" readonly>
          <input type="hidden" name="exco_auto" id="exco_auto" value="<?= htmlspecialchars($autoExcoDisplay) ?>">
          <div class="pill-note">Auto-assigned from the selected District.</div>
        </div>

        <div>
          <label>AJK (Selected)</label>
          <?php
            $currentExcoSelect = trim((string)$user['exco_select']);
            $opts = $ajk_all;
            if ($currentExcoSelect !== '' && !in_array($currentExcoSelect, $opts, true)) {
                array_unshift($opts, $currentExcoSelect);
            }
          ?>
          <select name="exco_select" id="exco_select">
            <option value="">— None —</option>
            <?php foreach ($opts as $nm): ?>
              <option value="<?= htmlspecialchars($nm,ENT_QUOTES) ?>" <?= ($currentExcoSelect===$nm?'selected':'') ?>><?= htmlspecialchars($nm) ?></option>
            <?php endforeach; ?>
          </select>
          <div class="pill-note">Shows <b>all AJK</b> across districts.</div>
        </div>

        <div>
          <label>Role</label>
          <select name="role" <?= column_exists($conn,'members','role')?'required':'' ?>>
            <?php foreach (['admin','exco','ajk','member'] as $r): ?>
              <option value="<?= htmlspecialchars($r) ?>" <?= ($user['role']===$r?'selected':'') ?>><?= htmlspecialchars(ucfirst($r)) ?></option>
            <?php endforeach; ?>
          </select>
          <div class="pill-note">Rule: only <b>one active EXCO</b> per District.</div>
        </div>

        <!-- Status + Reason -->
        <div>
          <label>Account Status</label>
          <select name="status" id="statusSelect" required>
            <?php foreach ([1=>'Active', 0=>'Inactive'] as $val=>$label): ?>
              <option value="<?= $val ?>" <?= ((int)$user['status']===$val?'selected':'') ?>><?= htmlspecialchars($label) ?></option>
            <?php endforeach; ?>
          </select>
          <div class="pill-note">If set to <b>Inactive</b>, a deactivation reason is required.</div>
        </div>
        <div id="deactReasonWrap" style="<?= ((int)$user['status']===0?'':'display:none;') ?>">
          <label>Reason of Deactivate</label>
          <select name="deactivated_reason_id" id="deactReason">
            <option value="">— Select reason —</option>
            <?php foreach ($deactReasons as $r): ?>
              <option value="<?= (int)$r['id'] ?>" <?= ((int)($user['deactivated_reason_id'] ?? 0)===(int)$r['id']?'selected':'') ?>>
                <?= htmlspecialchars($r['reason_text']) ?>
              </option>
            <?php endforeach; ?>
          </select>
        </div>

        <div class="full"><h3 class="section-title">Next of Kin Information</h3></div>
        <div>
          <label>Next of Kin Name</label>
          <input type="text" name="waris_name" value="<?= htmlspecialchars($user['waris_name'] ?? '') ?>" maxlength="150" autocomplete="off">
        </div>
        <div>
          <label>Next of Kin Phone Number</label>
          <input type="text" name="waris_phone" value="<?= htmlspecialchars($user['waris_phone'] ?? '') ?>" maxlength="20"
                 pattern="^[0-9+\-\s]{7,20}$" inputmode="tel" title="Hanya nombor / + / - / ruang (7–20 aksara)" data-phonemask="my">
        </div>

        <div class="full row-actions">
          <button type="submit" class="btn primary">Update Member</button>
          <a href="user-management.php" class="btn neutral">Cancel</a>
        </div>
      </div>
    </form>
  </div>

  <div class="card danger-zone">
    <h3 class="section-title" style="margin-bottom:6px">Danger Zone</h3>
    <div class="muted" style="margin-bottom:10px">Deleting this member will permanently remove the record.</div>
    <form method="post" onsubmit="return confirm('Are you sure you want to DELETE this member? This action is irreversible.');">
      <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
      <input type="hidden" name="delete_member" value="1">
      <button type="submit" class="btn danger">Delete Member</button>
    </form>
  </div>
</div>

<script>
(function(){
  // Toggle deactivate reason
  const statusSel = document.getElementById('statusSelect');
  const wrap      = document.getElementById('deactReasonWrap');
  const reasonSel = document.getElementById('deactReason');
  function toggleReason(){
    if (!statusSel || !wrap) return;
    if (statusSel.value === '0') {
      wrap.style.display = '';
      reasonSel && reasonSel.setAttribute('required','required');
    } else {
      wrap.style.display = 'none';
      reasonSel && reasonSel.removeAttribute('required');
      if (reasonSel) reasonSel.value = '';
    }
  }
  statusSel && statusSel.addEventListener('change', toggleReason);
  toggleReason();

  // Auto-hide flash after 4s
  const fb = document.getElementById('flashBox');
  if (fb) { setTimeout(()=>{ if(fb){ fb.style.transition='opacity .4s'; fb.style.opacity='0'; setTimeout(()=>fb.remove(), 400); } }, 4000); window.scrollTo({top:0,behavior:'smooth'}); }

  /* ========= Malaysia phone auto-mask ========= */
  function formatMYPhone(raw){
    if (!raw) return '';
    raw = String(raw).replace(/\s+/g,'');
    const hasPlus = raw[0] === '+';
    let digits = raw.replace(/[^\d]/g, '');
    if (hasPlus) {
      if (digits.startsWith('60')) {
        digits = digits.slice(2);
        return '+60 ' + localFormat(digits);
      }
      return '+' + genericFormat(digits);
    }
    return localFormat(digits);
  }
  function localFormat(d){
    if (!d) return '';
    if (d.startsWith('01')) {
      if (d.length >= 11) { const a=d.slice(0,3), b=d.slice(3,7), c=d.slice(7,11); return [a,b,c].filter(Boolean).join('-'); }
      if (d.length >= 10) { const a=d.slice(0,3), b=d.slice(3,10); return [a,b].join('-'); }
      if (d.length > 3)   { const a=d.slice(0,3), rest=d.slice(3); return a + '-' + rest; }
      return d;
    }
    if (/^0[3-9]/.test(d)) {
      const a = d.slice(0,2), rest = d.slice(2);
      if (rest.length >= 8) return a + '-' + rest.slice(0,4) + ' ' + rest.slice(4,8);
      if (rest.length >= 7) return a + '-' + rest.slice(0,3) + ' ' + rest.slice(3,7);
      if (rest.length > 0) return a + '-' + rest;
      return a;
    }
    return genericFormat(d);
  }
  function genericFormat(d){
    if (d.length >= 10) return d.slice(0,3) + '-' + d.slice(3,6) + '-' + d.slice(6,10);
    if (d.length > 6)   return d.slice(0,3) + '-' + d.slice(3,6) + '-' + d.slice(6);
    if (d.length > 3)   return d.slice(0,3) + '-' + d.slice(3);
    return d;
  }
  function attachPhoneMask(el){
    if (!el) return;
    const handle = ()=>{
      el.value = formatMYPhone(el.value);
      try { el.setSelectionRange(el.value.length, el.value.length); } catch(e){}
    };
    el.addEventListener('input', handle);
    el.addEventListener('keyup', handle);
    el.addEventListener('paste', ()=>{ setTimeout(handle, 0); });
    el.value = formatMYPhone(el.value);
  }
  document.querySelectorAll('input[data-phonemask="my"]').forEach(attachPhoneMask);

  /* ========= District ↔ Work Location (AJAX) ========= */
  const selDistrict = document.getElementById('district_id');
  const selWorkloc  = document.getElementById('work_location_id');
  const excoDisp    = document.getElementById('exco_auto_display');
  const excoHidden  = document.getElementById('exco_auto');

  async function fetchJSON(url){
    const res = await fetch(url, { credentials: 'same-origin', headers: {'X-Requested-With':'fetch'} });
    if (!res.ok) throw new Error('Network error');
    return res.json();
  }
  function setOptions(select, options, selectedVal, placeholder){
    if (!select) return;
    select.innerHTML = '';
    const opt0 = document.createElement('option');
    opt0.value = ''; opt0.textContent = placeholder || '— Optional —';
    select.appendChild(opt0);
    (options || []).forEach(o=>{
      const op = document.createElement('option');
      op.value = String(o.id); op.textContent = o.name;
      if (String(selectedVal||'') === String(o.id)) op.selected = true;
      select.appendChild(op);
    });
  }
  function clearExcoAuto(){
    if (excoDisp) excoDisp.value = '';
    if (excoHidden) excoHidden.value = '';
  }
  async function refreshExcoName(){
    if (!selDistrict) return;
    try{
      const did = parseInt(selDistrict.value||'0',10);
      if (!did) { clearExcoAuto(); return; }
      const j = await fetchJSON('user-edit.php?ajax=exco_name&district_id='+encodeURIComponent(did)+'&id=<?= (int)$id ?>');
      const nm = (j && j.ok && j.data) ? (j.data.name || '') : '';
      if (excoDisp) excoDisp.value = nm;
      if (excoHidden) excoHidden.value = nm;
    }catch(e){ /* ignore UI error */ }
  }

  async function refreshWorkLocations(keepCurrent=false){
    if (!selDistrict || !selWorkloc) return;
    const did = parseInt(selDistrict.value||'0',10);
    try{
      const j = await fetchJSON('user-edit.php?ajax=work_locations&district_id='+encodeURIComponent(did)+'&id=<?= (int)$id ?>');
      const rows = (j && j.ok && Array.isArray(j.data)) ? j.data : [];
      const selectedVal = keepCurrent ? selWorkloc.value : '';
      setOptions(selWorkloc, rows, selectedVal, '— Optional —');
      // If current selection no longer in list, clear it
      if (selWorkloc.value && !rows.find(r => String(r.id) === String(selWorkloc.value))) {
        selWorkloc.value = '';
      }
    }catch(e){
      setOptions(selWorkloc, [], '', '— Optional —');
    }
  }

  // District change -> reload WL + update EXCO name
  if (selDistrict) {
    selDistrict.addEventListener('change', async function(){
      await refreshWorkLocations(false);
      await refreshExcoName();
    });
  }

  // Workloc change -> snap District (bi-directional) + update EXCO name
  if (selWorkloc) {
    selWorkloc.addEventListener('change', async function(){
      const wlId = parseInt(this.value||'0',10);
      if (!wlId) { clearExcoAuto(); return; }
      try{
        const j = await fetchJSON('user-edit.php?ajax=district_by_workloc&work_location_id='+encodeURIComponent(wlId)+'&id=<?= (int)$id ?>');
        const did = (j && j.ok && j.data) ? parseInt(j.data.district_id||'0',10) : 0;
        if (did && selDistrict && String(selDistrict.value) !== String(did)) {
          selDistrict.value = String(did);
          await refreshWorkLocations(true); // keep the currently chosen WL in the new list
        }
        await refreshExcoName();
      }catch(e){ clearExcoAuto(); }
    });
  }

  // On first load: ensure EXCO field reflects current district (already server-filled, but refresh once)
  refreshExcoName();
})();
</script>

<?php
$content = ob_get_clean();
include __DIR__ . '/layout.php';
