<?php
/**
 * subscription_lib.php
 * Include this file wherever you need to:
 *  - auto-activate a trial plan for a new user
 *  - check whether a user can create/pay one more transaction
 *  - count a transaction against the user's current period
 *
 * Usage:
 *   include ROOT_DIR . 'includes/subscription_lib.php';
 */

/**
 * Work out end_date for a plan starting today, based on expiry (number)
 * and period_type (day/week/month/year).
 */
function sub_calculate_end_date($period_type, $expiry_units, $start_date = null) {
    $start_date = $start_date ?: date('Y-m-d');
    $unit_map = [
        'day'   => 'day',
        'week'  => 'week',
        'month' => 'month',
        'year'  => 'year',
    ];
    $unit = isset($unit_map[$period_type]) ? $unit_map[$period_type] : 'month';
    $expiry_units = max(1, (int)$expiry_units);
    return date('Y-m-d', strtotime("$start_date +{$expiry_units} {$unit}"));
}

/**
 * Assign the Trial plan to a brand-new user. Call right after a
 * successful INSERT into `users` (pass the new user's id).
 * Also updates users.expiry so existing "expiry >= today" checks
 * elsewhere in the codebase keep working automatically.
 */
function assignTrialPlan($conn, $user_id) {
    $trial = mysqli_query($conn, "SELECT * FROM subscription_plan WHERE is_trial = 1 AND status='Active' LIMIT 1");
    if (!$trial || mysqli_num_rows($trial) === 0) {
        return false; // no trial plan configured, nothing to do
    }
    $plan = mysqli_fetch_assoc($trial);
    $start = date('Y-m-d');
    $end = sub_calculate_end_date($plan['period_type'], $plan['expiry'], $start);

    $user_id = (int)$user_id;
    $plan_id = (int)$plan['id'];
    $stmt = $conn->prepare("INSERT INTO user_subscriptions (user_id, plan_id, start_date, end_date, period_start, transactions_used, status) VALUES (?, ?, ?, ?, ?, 0, 'Active')");
    $stmt->bind_param("issss", $user_id, $plan_id, $start, $end, $start);
    $stmt->execute();
    $stmt->close();

    // Keep users.expiry in sync so old code paths (create_order.php etc.)
    // that check `expiry >= today` keep behaving correctly.
    $stmt2 = $conn->prepare("UPDATE users SET expiry = ? WHERE id = ?");
    $stmt2->bind_param("si", $end, $user_id);
    $stmt2->execute();
    $stmt2->close();

    return true;
}

/**
 * Get the user's current active subscription row (joined with plan info).
 * Returns null if the user has no active subscription record (older
 * accounts created before this system existed).
 */
function getActiveSubscription($conn, $user_id) {
    $user_id = (int)$user_id;
    $sql = "SELECT us.*, sp.plan_name, sp.max_transactions, sp.period_type, sp.expiry AS plan_expiry, sp.cashier_limit, sp.static_paylink_limit, sp.is_trial
            FROM user_subscriptions us
            JOIN subscription_plan sp ON sp.id = us.plan_id
            WHERE us.user_id = ? AND us.status = 'Active'
            ORDER BY us.id DESC LIMIT 1";
    $stmt = $conn->prepare($sql);
    if (!$stmt) {
        // A column/table this query needs doesn't exist yet (migration not
        // run). Fail safe instead of a blank fatal-error page - treat it as
        // "no active subscription" everywhere this function is called.
        error_log('getActiveSubscription() query failed: ' . $conn->error);
        return null;
    }
    $stmt->bind_param("i", $user_id);
    $stmt->execute();
    $res = $stmt->get_result();
    $row = $res->fetch_assoc();
    $stmt->close();

    if (!$row) return null;

    // Lazily flip to Expired here too (not just in checkTransactionQuota),
    // so every caller - including getCashierLimit() - sees the true state
    // even if a status field in the DB hasn't been updated yet.
    if (strtotime($row['end_date']) < strtotime(date('Y-m-d'))) {
        $id = (int)$row['id'];
        $conn->query("UPDATE user_subscriptions SET status='Expired' WHERE id = $id");
        return null;
    }

    return $row;
}

/**
 * Roll the usage counter over to a fresh period if the current
 * period_start has elapsed (e.g. a monthly plan ticking over to the
 * next month while still inside the overall plan end_date).
 */
function sub_roll_period_if_needed($conn, $sub) {
    $period_end = sub_calculate_end_date($sub['period_type'], 1, $sub['period_start']); // one period length
    if (date('Y-m-d') >= $period_end && date('Y-m-d') < $sub['end_date']) {
        $new_period_start = date('Y-m-d');
        $stmt = $conn->prepare("UPDATE user_subscriptions SET period_start = ?, transactions_used = 0 WHERE id = ?");
        $id = (int)$sub['id'];
        $stmt->bind_param("si", $new_period_start, $id);
        $stmt->execute();
        $stmt->close();
        $sub['period_start'] = $new_period_start;
        $sub['transactions_used'] = 0;
    }
    return $sub;
}

/**
 * Main guard: call this BEFORE creating a new payment order.
 * Returns ['allowed' => bool, 'message' => string].
 */
function checkTransactionQuota($conn, $user_id) {
    $sub = getActiveSubscription($conn, $user_id);

    if (!$sub) {
        // No active subscription right now. Was this account created
        // under the new "must buy a plan" system (requires_plan='Yes')?
        // If so, block them - they need to purchase/activate a plan first.
        // Older accounts created before this system existed don't have
        // requires_plan set, so they keep working as before (grandfathered).
        $uid = (int)$user_id;
        $queryResult = $conn->query("SELECT requires_plan FROM users WHERE id = $uid");
        $userRow = $queryResult ? $queryResult->fetch_assoc() : null;
        if ($userRow && $userRow['requires_plan'] === 'Yes') {
            return ['allowed' => false, 'message' => 'Please purchase a subscription plan to start accepting payments.'];
        }
        return ['allowed' => true, 'message' => 'OK'];
    }

    if (strtotime($sub['end_date']) < strtotime(date('Y-m-d'))) {
        // Plan fully expired
        $id = (int)$sub['id'];
        $conn->query("UPDATE user_subscriptions SET status='Expired' WHERE id = $id");
        return ['allowed' => false, 'message' => 'Your subscription has expired. Please renew your plan.'];
    }

    $sub = sub_roll_period_if_needed($conn, $sub);

    $max = (int)$sub['max_transactions'];
    if ($max > 0 && (int)$sub['transactions_used'] >= $max) {
        return ['allowed' => false, 'message' => "You have used all {$max} transactions allowed in your current {$sub['period_type']} for the \"{$sub['plan_name']}\" plan. Please upgrade your plan."];
    }

    return ['allowed' => true, 'message' => 'OK'];
}

/**
 * Call this AFTER an order is confirmed successful (i.e. inside your
 * payment_status.php success branch), so only real successful
 * transactions count against the plan - not abandoned/failed ones.
 */
function incrementTransactionUsage($conn, $user_id) {
    $sub = getActiveSubscription($conn, $user_id);
    if (!$sub) return;
    $id = (int)$sub['id'];
    $conn->query("UPDATE user_subscriptions SET transactions_used = transactions_used + 1 WHERE id = $id");
}

/**
 * How many merchant/cashier accounts is this user allowed to connect.
 */
function getCashierLimit($conn, $user_id) {
    $sub = getActiveSubscription($conn, $user_id);
    if (!$sub) {
        $uid = (int)$user_id;
        $queryResult = $conn->query("SELECT requires_plan FROM users WHERE id = $uid");
        $userRow = $queryResult ? $queryResult->fetch_assoc() : null;
        if ($userRow && $userRow['requires_plan'] === 'Yes') {
            return 0; // must buy a plan before connecting any merchant
        }
        return 1; // legacy account, safe default
    }
    return (int)$sub['cashier_limit'];
}

/**
 * How many Static Paylinks this user is allowed to create in total
 * (0 = unlimited). Returns 0 (blocked) for accounts under the new
 * "must buy a plan" system with no active subscription; legacy accounts
 * with no subscription history at all default to 1 so nothing breaks.
 */
function getStaticPaylinkLimit($conn, $user_id) {
    $sub = getActiveSubscription($conn, $user_id);
    if (!$sub) {
        $uid = (int)$user_id;
        $queryResult = $conn->query("SELECT requires_plan FROM users WHERE id = $uid");
        $userRow = $queryResult ? $queryResult->fetch_assoc() : null;
        if ($userRow && $userRow['requires_plan'] === 'Yes') {
            return -1; // -1 = "must buy a plan first", distinct from 0=unlimited
        }
        return 1; // legacy account, safe default
    }
    return (int)($sub['static_paylink_limit'] ?? 1);
}

/**
 * Call this when a user purchases/upgrades a plan (from subscription.php's
 * "Buy Now" flow, after payment for the plan itself succeeds). Deactivates
 * any existing active subscription and starts the new one.
 */
function activatePlanForUser($conn, $user_id, $plan_id) {
    $user_id = (int)$user_id;
    $plan_id = (int)$plan_id;

    $conn->query("UPDATE user_subscriptions SET status='Cancelled' WHERE user_id = $user_id AND status='Active'");

    $planRes = $conn->query("SELECT * FROM subscription_plan WHERE id = $plan_id LIMIT 1");
    if (!$planRes || $planRes->num_rows === 0) return false;
    $plan = $planRes->fetch_assoc();

    $start = date('Y-m-d');
    $end = sub_calculate_end_date($plan['period_type'], $plan['expiry'], $start);

    $stmt = $conn->prepare("INSERT INTO user_subscriptions (user_id, plan_id, start_date, end_date, period_start, transactions_used, status) VALUES (?, ?, ?, ?, ?, 0, 'Active')");
    $stmt->bind_param("issss", $user_id, $plan_id, $start, $end, $start);
    $stmt->execute();
    $stmt->close();

    $stmt2 = $conn->prepare("UPDATE users SET expiry = ? WHERE id = ?");
    $stmt2->bind_param("si", $end, $user_id);
    $stmt2->execute();
    $stmt2->close();

    return true;
}
