<?php
require_once __DIR__ . '/../app/bootstrap.php';

use App\Core\Auth;
use App\Core\Database;
use App\Core\Response;
use App\Core\Security;
use App\Core\WalletService;

Auth::requireRole(['affiliate', 'customer', 'admin']);
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !verify_csrf()) {
    Response::json(['ok' => false, 'message' => 'Invalid request.'], 419);
}
$data = request_data();
$plan = Database::safeFetchOne('SELECT * FROM affiliate_plans WHERE id=? AND status="active" LIMIT 1', [(int)($data['plan_id'] ?? 0)]);
if (!$plan) Response::json(['ok' => false, 'message' => 'Plan not found.'], 404);

try {
    $membershipId = Database::transaction(function () use ($plan): int {
        $userId = (int)Auth::id();
        $user = Database::fetchOne('SELECT id,role,status FROM users WHERE id=? LIMIT 1 FOR UPDATE', [$userId]);
        if (!$user || !in_array((string)$user['status'], ['active', 'approved'], true)) {
            throw new RuntimeException('The account is unavailable.');
        }
        $existingPlan = Database::fetchOne(
            'SELECT amp.id,amp.plan_id FROM affiliate_member_plans amp JOIN affiliate_members am ON am.id=amp.affiliate_member_id WHERE am.user_id=? AND amp.status="active" AND (amp.ends_at IS NULL OR amp.ends_at>=CURDATE()) ORDER BY amp.id DESC LIMIT 1 FOR UPDATE',
            [$userId]
        );
        if ($existingPlan && (int)$existingPlan['plan_id'] === (int)$plan['id']) {
            throw new RuntimeException('This affiliate plan is already active.');
        }
        if ((float)$plan['price'] > 0 && !WalletService::debit($userId, 'purchase', (float)$plan['price'], 'Affiliate plan ' . $plan['name'], (int)$plan['id'])) {
            throw new RuntimeException('Insufficient purchase-wallet balance.');
        }

        $member = Database::fetchOne('SELECT * FROM affiliate_members WHERE user_id=? LIMIT 1 FOR UPDATE', [$userId]);
        if (!$member) {
            do {
                $code = 'PH' . strtoupper(substr(bin2hex(random_bytes(6)), 0, 10));
            } while (Database::safeFetchOne('SELECT id FROM affiliate_members WHERE referral_code=? LIMIT 1', [$code]));
            Database::execute(
                'INSERT INTO affiliate_members (user_id,referral_code,rank_code,status,created_at,updated_at) VALUES (?,? ,"IBO","active",NOW(),NOW())',
                [$userId, $code]
            );
            $member = ['id' => Database::lastInsertId()];
        } else {
            Database::execute('UPDATE affiliate_members SET status="active",updated_at=NOW() WHERE id=?', [$member['id']]);
        }

        Database::execute('UPDATE affiliate_member_plans SET status="expired" WHERE affiliate_member_id=? AND status="active"', [$member['id']]);
        Database::execute(
            'INSERT INTO affiliate_member_plans (affiliate_member_id,plan_id,starts_at,ends_at,status) VALUES (?,?,CURDATE(),DATE_ADD(CURDATE(),INTERVAL 365 DAY),"active")',
            [$member['id'], $plan['id']]
        );
        $membershipId = Database::lastInsertId();
        if ((string)$user['role'] === 'customer') {
            Database::execute('UPDATE users SET role="affiliate",updated_at=NOW() WHERE id=?', [$userId]);
            $_SESSION['role'] = 'affiliate';
        }
        return $membershipId;
    });
    Security::logActivity(Auth::id(), 'affiliate_plan_activated', ['plan_id' => $plan['id'], 'membership_id' => $membershipId]);
    Response::json(['ok' => true, 'membership_id' => $membershipId, 'message' => 'Affiliate plan activated.']);
} catch (Throwable $exception) {
    Response::json(['ok' => false, 'message' => $exception->getMessage()], 422);
}
