<?php
/* ============================================================================
 *  config/approvals.php — two-stage approval chain logic.
 *  Stage 1: the staff member's Department Manager.
 *  Stage 2: the company's Operation Manager (final).
 *  Status flow: pending -> dept_ok -> approved   (or rejected at any stage).
 *
 *  Two-step is only ENFORCED when an Operation Manager is set in
 *  company_approval_settings. Otherwise the old one-step behaviour stays.
 * ==========================================================================*/
require_once __DIR__ . '/notify.php';

function appr_settings(PDO $pdo, int $companyId): array {
    $ops = 0; $req = 1; $owner = 0;
    try {
        $s = $pdo->prepare("SELECT final_manager_id, require_dept, owner_user_id FROM company_approval_settings WHERE company_id=? LIMIT 1");
        $s->execute([$companyId]);
        if ($r = $s->fetch(PDO::FETCH_ASSOC)) { $ops = (int)$r['final_manager_id']; $req = (int)$r['require_dept']; $owner = (int)($r['owner_user_id'] ?? 0); }
    } catch (Throwable $e) {
        /* owner_user_id column may not exist yet — fall back without it */
        try {
            $s = $pdo->prepare("SELECT final_manager_id, require_dept FROM company_approval_settings WHERE company_id=? LIMIT 1");
            $s->execute([$companyId]);
            if ($r = $s->fetch(PDO::FETCH_ASSOC)) { $ops = (int)$r['final_manager_id']; $req = (int)$r['require_dept']; }
        } catch (Throwable $e2) {}
    }
    return ['ops' => $ops, 'require_dept' => $req, 'owner' => $owner];
}

/* The company Owner / Founder (users.id), or 0. */
function appr_owner(PDO $pdo, int $companyId): int {
    return appr_settings($pdo, $companyId)['owner'];
}
function appr_is_owner(PDO $pdo, int $companyId, int $userId): bool {
    $o = appr_owner($pdo, $companyId);
    return $o > 0 && $userId === $o;
}

/* department manager (users.id) of a staff member's department, or 0 */
function appr_dept_manager(PDO $pdo, int $companyId, int $staffUserId): int {
    try {
        $st = $pdo->prepare("SELECT d.manager_user_id
            FROM company_staff cs
            JOIN company_departments d ON d.company_id = cs.company_id AND d.name = cs.department
            WHERE cs.user_id = ? AND cs.company_id = ? LIMIT 1");
        $st->execute([$staffUserId, $companyId]);
        return (int)$st->fetchColumn();
    } catch (Throwable $e) { return 0; }
}

/* Is the two-step chain active for this company? */
function appr_enabled(PDO $pdo, int $companyId): bool {
    return appr_settings($pdo, $companyId)['ops'] > 0;
}

/* Active stand-in (delegate) for a manager, or 0. */
function appr_delegate_of(PDO $pdo, int $companyId, int $managerId): int {
    if ($managerId <= 0) return 0;
    try {
        $st = $pdo->prepare("SELECT to_user_id FROM approval_delegates
                             WHERE company_id=? AND from_user_id=? AND (until_date IS NULL OR until_date>=CURDATE()) LIMIT 1");
        $st->execute([$companyId, $managerId]);
        return (int)$st->fetchColumn();
    } catch (Throwable $e) { return 0; }
}

/* True if the reviewer IS the manager, or is the manager's active delegate. */
function appr_is_or_delegate(PDO $pdo, int $companyId, int $reviewerId, int $managerId): bool {
    if ($managerId <= 0) return false;
    if ($reviewerId === $managerId) return true;
    return $reviewerId === appr_delegate_of($pdo, $companyId, $managerId);
}

/* Reviewer's role relative to one request. */
function appr_ctx(PDO $pdo, int $companyId, int $reviewerId, int $staffUserId): array {
    $s = appr_settings($pdo, $companyId);
    $dept = appr_dept_manager($pdo, $companyId, $staffUserId);
    return [
        'ops' => $s['ops'],
        'require_dept' => $s['require_dept'],
        'dept' => $dept,
        'isOps' => ($s['ops'] > 0 && appr_is_or_delegate($pdo, $companyId, $reviewerId, $s['ops'])),
        'isDept' => ($dept > 0 && $s['require_dept'] == 1 && appr_is_or_delegate($pdo, $companyId, $reviewerId, $dept)),
        'isOwner' => ($s['owner'] > 0 && appr_is_or_delegate($pdo, $companyId, $reviewerId, $s['owner'])),
    ];
}

/* On APPROVE: the next status, or null if this reviewer can't approve now. */
function appr_next(string $current, array $ctx): ?string {
    if (!in_array($current, ['pending', 'dept_ok'], true)) return null;
    if (!empty($ctx['isOwner'])) return 'approved';                  // Owner override — finalize at any stage
    if ($current === 'pending') {
        if ($ctx['isOps'])  return 'approved';                       // Ops is final; also covers dept
        if ($ctx['isDept']) return ($ctx['ops'] > 0) ? 'dept_ok' : 'approved';
        return null;
    }
    if ($current === 'dept_ok') {
        if ($ctx['isOps']) return 'approved';
        return null;
    }
    return null;
}

/* Can this reviewer reject the request at its current stage? */
function appr_can_reject(string $current, array $ctx): bool {
    return in_array($current, ['pending', 'dept_ok'], true) && (!empty($ctx['isOwner']) || $ctx['isOps'] || $ctx['isDept']);
}

/* Approval routing is "active" if an Operation Manager is set OR any
   department has a manager assigned (so dept-manager approval works even
   without an Operation Manager). */
function appr_active(PDO $pdo, int $companyId): bool {
    if (appr_enabled($pdo, $companyId)) return true;
    try {
        $s = $pdo->prepare("SELECT COUNT(*) FROM company_departments WHERE company_id=? AND manager_user_id IS NOT NULL AND manager_user_id>0");
        $s->execute([$companyId]);
        return (int)$s->fetchColumn() > 0;
    } catch (Throwable $e) { return false; }
}

/* Is this user allowed to review requests at all (dept manager, Operation
   Manager, Owner, or an active delegate of any of those)? */
function appr_is_reviewer(PDO $pdo, int $companyId, int $userId): bool {
    if ($userId <= 0) return false;
    try {
        $s = appr_settings($pdo, $companyId);
        if ($s['ops'] === $userId || $s['owner'] === $userId) return true;
        if ($s['ops']   > 0 && appr_delegate_of($pdo, $companyId, $s['ops'])   === $userId) return true;
        if ($s['owner'] > 0 && appr_delegate_of($pdo, $companyId, $s['owner']) === $userId) return true;
        // any department manager, or delegate of one
        $st = $pdo->prepare("SELECT manager_user_id FROM company_departments WHERE company_id=? AND manager_user_id IS NOT NULL AND manager_user_id>0");
        $st->execute([$companyId]);
        foreach ($st->fetchAll(PDO::FETCH_COLUMN) as $mgr) {
            $mgr = (int)$mgr;
            if ($mgr === $userId) return true;
            if (appr_delegate_of($pdo, $companyId, $mgr) === $userId) return true;
        }
        return false;
    } catch (Throwable $e) { return false; }
}

/* Departments (lowercased names) that this user manages directly or as a delegate. */
function appr_my_department_names(PDO $pdo, int $companyId, int $userId): array {
    $mine = [];
    try {
        $dq = $pdo->prepare("SELECT name FROM company_departments WHERE company_id=? AND manager_user_id=?");
        $dq->execute([$companyId, $userId]);
        foreach ($dq->fetchAll(PDO::FETCH_COLUMN) as $dn) { $mine[] = mb_strtolower(trim((string)$dn)); }
        $dq2 = $pdo->prepare("SELECT name, manager_user_id FROM company_departments WHERE company_id=? AND manager_user_id IS NOT NULL");
        $dq2->execute([$companyId]);
        foreach ($dq2->fetchAll(PDO::FETCH_ASSOC) as $row) {
            if (appr_delegate_of($pdo, $companyId, (int)$row['manager_user_id']) === $userId) { $mine[] = mb_strtolower(trim((string)$row['name'])); }
        }
    } catch (Throwable $e) {}
    return array_values(array_unique($mine));
}

/* Count of leave requests currently awaiting THIS reviewer's action. */
function appr_leave_pending_for(PDO $pdo, int $companyId, int $userId): int {
    if ($userId <= 0) return 0;
    try {
        $s = appr_settings($pdo, $companyId);
        $isOpsOwner = ($s['ops'] === $userId || $s['owner'] === $userId
            || ($s['ops']   > 0 && appr_delegate_of($pdo,$companyId,$s['ops'])   === $userId)
            || ($s['owner'] > 0 && appr_delegate_of($pdo,$companyId,$s['owner']) === $userId));
        if ($isOpsOwner) {
            $q = $pdo->prepare("SELECT COUNT(*) FROM hr_leave WHERE company_id=? AND status IN ('pending','dept_ok')");
            $q->execute([$companyId]);
            return (int)$q->fetchColumn();
        }
        // department manager: count pending (stage 1) requests from their department(s)
        $mine = appr_my_department_names($pdo, $companyId, $userId);
        if (!$mine) return 0;
        $q = $pdo->prepare("SELECT cs.department FROM hr_leave l
                            LEFT JOIN company_staff cs ON cs.user_id=l.staff_id AND cs.company_id=l.company_id
                            WHERE l.company_id=? AND l.status='pending'");
        $q->execute([$companyId]);
        $n = 0;
        foreach ($q->fetchAll(PDO::FETCH_COLUMN) as $dep) {
            if (in_array(mb_strtolower(trim((string)$dep)), $mine, true)) $n++;
        }
        return $n;
    } catch (Throwable $e) { return 0; }
}

/* Colour + EN/Lao label for a status (incl. the new dept_ok stage). */
function appr_label(string $status): array {
    switch ($status) {
        case 'pending':  return ['amber', 'Waiting: Dept Manager', 'ລໍຖ້າ: ຫົວໜ້າພະແນກ'];
        case 'dept_ok':  return ['blue',  'Waiting: Operation Manager', 'ລໍຖ້າ: ຜູ້ຈັດການ'];
        case 'approved': return ['green', 'Approved', 'ອະນຸມັດແລ້ວ'];
        case 'rejected': return ['red',   'Rejected', 'ປະຕິເສດ'];
        default:         return ['gray',  ucfirst($status), $status];
    }
}