<?php
/**
 * approval_notify.php
 * -------------------------------------------------------------------
 * Shared "who do we email, and what do we say" logic for the payroll
 * approval workflow. Used by:
 *   - cycles.php: Request Approval (fresh) / Resend Reminder (manual
 *     fallback, e.g. if an earlier email failed to send or land)
 *   - cycle_approve.php: automatically notifying the NEXT stage's
 *     approver(s) the moment the current stage is approved, so the
 *     approval chain doesn't just silently stall waiting on someone who
 *     was never told it's their turn.
 *
 * Deliberately does NOT require Mailer.php (and therefore PHPMailer) at
 * this file's top level -- only inside notifyStageApprovers()'s own try
 * block, so simply including this file can never break a page that
 * doesn't end up needing to send anything.
 * -------------------------------------------------------------------
 */

function buildAbsoluteUrl(string $relativePath): string
{
    $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
    $host = $_SERVER['HTTP_HOST'] ?? 'localhost';
    $dir = rtrim(str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'])), '/');
    return "$scheme://$host$dir/$relativePath";
}

/**
 * Resolves and emails the approver(s) for a single stage, about a single
 * cycle: everyone matching a role-based stage's role, or the one specific
 * user for a user-based stage -- same model cycle_approve.php already uses
 * to decide who's ALLOWED to act on a stage, just extended to also decide
 * who gets told about it.
 *
 * @return array{sent: int, skippedNoEmail: int, error: string|null}
 */
function notifyStageApprovers(mysqli $conn, array $cycleRow, array $stage): array
{
    $approvers = [];
    if ($stage['approver_type'] === 'role') {
        $roleStmt = $conn->prepare("SELECT username, email FROM users WHERE role = ?");
        $roleStmt->bind_param('s', $stage['approver_role']);
        $roleStmt->execute();
        $roleRes = $roleStmt->get_result();
        while ($u = $roleRes->fetch_assoc()) { $approvers[] = $u; }
        $roleStmt->close();
    } else {
        $userStmt = $conn->prepare("SELECT username, email FROM users WHERE id = ?");
        $userStmt->bind_param('i', $stage['approver_user_id']);
        $userStmt->execute();
        $u = $userStmt->get_result()->fetch_assoc();
        if ($u) { $approvers[] = $u; }
        $userStmt->close();
    }

    $approvalUrl = buildAbsoluteUrl('cycle_approve.php?cycle_id=' . (int) $cycleRow['id']);
    $sent = 0;
    $skippedNoEmail = 0;

    try {
        require_once __DIR__ . '/Mailer.php';
        $mailer = new Mailer($conn);
        $body = Mailer::approvalRequestEmailTemplate($cycleRow, $approvalUrl, $stage['stage_name']);
        foreach ($approvers as $approver) {
            if (empty($approver['email'])) { $skippedNoEmail++; continue; }
            $result = $mailer->send($approver['email'], $approver['username'], 'Payroll Approval Requested: ' . $cycleRow['name'], $body);
            if ($result['success']) { $sent++; }
        }
    } catch (Throwable $e) {
        // Catches Exception AND Error/TypeError alike -- e.g. PHPMailer not
        // installed, or (before a related fix) Mailer's own constructor
        // crashing outright if email_settings has no active row. Whatever
        // the cause, this is meant to always degrade to a reportable error
        // rather than take down the whole approve/reject or request-
        // approval action with an uncaught fatal error.
        return ['sent' => 0, 'skippedNoEmail' => 0, 'error' => $e->getMessage()];
    }

    return ['sent' => $sent, 'skippedNoEmail' => $skippedNoEmail, 'error' => null];
}
