<?php
require __DIR__ . '/bootstrap.php';

use App\Core\Auth;
use App\Core\Csrf;
use App\Core\Database;
use App\Core\Response;
use App\Core\Security;
use App\Services\TierService;

$user = Auth::requireUser();
$pdo = Database::connection();
$input = request_input();
if ($_POST) $input = array_merge($input, $_POST);
$method = $_SERVER['REQUEST_METHOD'];
$action = $input['action'] ?? 'overview';

function pyrk_tiers_can_manage(array $user): void
{
    if (!Auth::hasPermission('tiers.manage', $user) && !Auth::hasPermission('loyalty.manage', $user) && !in_array($user['role_name'] ?? '', ['super_admin','event_manager'], true)) {
        Response::error('You do not have permission to manage loyalty tiers.', 403);
    }
}

function pyrk_tiers_table_exists(PDO $pdo, string $table): bool
{
    try {
        $stmt = $pdo->prepare('SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = ?');
        $stmt->execute([$table]);
        return (int)$stmt->fetchColumn() > 0;
    } catch (Throwable) {
        return false;
    }
}

function pyrk_tiers_require_tables(PDO $pdo): void
{
    if (!pyrk_tiers_table_exists($pdo, 'loyalty_tiers') || !pyrk_tiers_table_exists($pdo, 'member_tier_assignments') || !pyrk_tiers_table_exists($pdo, 'reward_sponsors') || !pyrk_tiers_table_exists($pdo, 'reward_tier_eligibility')) {
        Response::error('Loyalty tier tables are not installed yet. Run database/migrations/040_loyalty_tiers_sponsors_prizes.sql', 500);
    }
}

function pyrk_tiers_ids(mixed $value): array
{
    if (is_string($value)) {
        $decoded = json_decode($value, true);
        $value = is_array($decoded) ? $decoded : preg_split('/\s*,\s*/', $value);
    }
    if (!is_array($value)) $value = [];
    return array_values(array_unique(array_filter(array_map('intval', $value))));
}

function pyrk_tiers_badges(PDO $pdo): array
{
    try { return $pdo->query('SELECT id, badge_name, badge_icon, status FROM badges ORDER BY status ASC, badge_name ASC')->fetchAll(PDO::FETCH_ASSOC); }
    catch (Throwable) { return []; }
}

function pyrk_tiers_rewards(PDO $pdo): array
{
    try {
        $rows = $pdo->query('SELECT r.*, s.sponsor_name,
            (SELECT GROUP_CONCAT(rte.tier_id ORDER BY rte.tier_id) FROM reward_tier_eligibility rte WHERE rte.reward_id = r.id) AS tier_ids_csv
            FROM rewards r
            LEFT JOIN reward_sponsors s ON s.id = r.sponsor_id
            ORDER BY r.status ASC, r.reward_name ASC')->fetchAll(PDO::FETCH_ASSOC);
        foreach ($rows as &$row) {
            $row['tier_ids'] = array_values(array_filter(array_map('intval', explode(',', (string)($row['tier_ids_csv'] ?? '')))));
        }
        unset($row);
        return $rows;
    } catch (Throwable) { return []; }
}

function pyrk_tiers_members(PDO $pdo): array
{
    try {
        $sql = 'SELECT u.id, u.full_name, u.email, u.mobile, COALESCE(mp.loyalty_points,0) AS loyalty_points,
            (SELECT COUNT(*) FROM user_badges ub WHERE ub.user_id = u.id) AS badge_count,
            mta.tier_id, mta.assigned_at, mta.expires_at, lt.tier_name, lt.tier_code, lt.icon, lt.color
            FROM users u
            JOIN roles r ON r.id = u.role_id
            LEFT JOIN member_profiles mp ON mp.user_id = u.id
            LEFT JOIN member_tier_assignments mta ON mta.user_id = u.id AND mta.status = "active" AND (mta.expires_at IS NULL OR mta.expires_at >= NOW())
            LEFT JOIN loyalty_tiers lt ON lt.id = mta.tier_id
            WHERE r.name = "member"
            ORDER BY COALESCE(lt.sort_order, -1) DESC, mp.loyalty_points DESC, u.full_name ASC';
        return $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
    } catch (Throwable) { return []; }
}

function pyrk_tier_input(array $input): array
{
    $name = trim((string)($input['tier_name'] ?? ''));
    if ($name === '') Response::error('Tier name is required.');
    $code = strtolower(trim((string)($input['tier_code'] ?? preg_replace('/[^a-z0-9]+/i', '-', $name))));
    $code = trim(preg_replace('/[^a-z0-9_-]+/', '-', $code), '-_');
    if ($code === '') $code = strtolower(bin2hex(random_bytes(3)));
    $status = in_array(($input['status'] ?? 'active'), ['active','inactive'], true) ? $input['status'] : 'active';
    $badgeIds = pyrk_tiers_ids($input['required_badge_ids'] ?? $input['required_badges_json'] ?? []);
    return [
        'tier_name' => $name,
        'tier_code' => $code,
        'description' => trim((string)($input['description'] ?? '')),
        'icon' => trim((string)($input['icon'] ?? '🏅')) ?: '🏅',
        'color' => trim((string)($input['color'] ?? '#1c7c54')) ?: '#1c7c54',
        'min_points' => max(0, (int)($input['min_points'] ?? 0)),
        'required_badge_count' => max(0, (int)($input['required_badge_count'] ?? 0)),
        'required_badges_json' => $badgeIds ? json_encode($badgeIds) : null,
        'level_valid_days' => max(0, (int)($input['level_valid_days'] ?? 365)),
        'sort_order' => (int)($input['sort_order'] ?? 0),
        'status' => $status,
    ];
}

function pyrk_sponsor_input(array $input): array
{
    $name = trim((string)($input['sponsor_name'] ?? ''));
    if ($name === '') Response::error('Sponsor name is required.');
    $status = in_array(($input['status'] ?? 'active'), ['active','inactive'], true) ? $input['status'] : 'active';
    return [
        'sponsor_name' => $name,
        'contact_name' => trim((string)($input['contact_name'] ?? '')),
        'email' => trim((string)($input['email'] ?? '')),
        'phone' => trim((string)($input['phone'] ?? '')),
        'website' => trim((string)($input['website'] ?? '')),
        'logo_path' => trim((string)($input['logo_path'] ?? '')),
        'notes' => trim((string)($input['notes'] ?? '')),
        'status' => $status,
    ];
}

pyrk_tiers_can_manage($user);
pyrk_tiers_require_tables($pdo);

if ($method === 'GET' && $action === 'overview') {
    TierService::expireOldTiers($pdo);
    Response::ok([
        'tiers' => $pdo->query('SELECT * FROM loyalty_tiers ORDER BY status ASC, sort_order ASC, min_points ASC, tier_name ASC')->fetchAll(PDO::FETCH_ASSOC),
        'sponsors' => $pdo->query('SELECT * FROM reward_sponsors ORDER BY status ASC, sponsor_name ASC')->fetchAll(PDO::FETCH_ASSOC),
        'badges' => pyrk_tiers_badges($pdo),
        'rewards' => pyrk_tiers_rewards($pdo),
        'members' => pyrk_tiers_members($pdo),
        'expiring' => $pdo->query('SELECT mta.*, u.full_name, u.email, lt.tier_name, lt.icon FROM member_tier_assignments mta JOIN users u ON u.id = mta.user_id JOIN loyalty_tiers lt ON lt.id = mta.tier_id WHERE mta.status = "active" AND mta.expires_at IS NOT NULL AND mta.expires_at BETWEEN NOW() AND DATE_ADD(NOW(), INTERVAL 30 DAY) ORDER BY mta.expires_at ASC LIMIT 80')->fetchAll(PDO::FETCH_ASSOC),
    ]);
}

if ($method === 'POST' && $action === 'save_tier') {
    Csrf::validateFromRequest();
    $data = pyrk_tier_input($input);
    $id = (int)($input['id'] ?? 0);
    try {
        if ($id > 0) {
            $stmt = $pdo->prepare('UPDATE loyalty_tiers SET tier_name=?, tier_code=?, description=?, icon=?, color=?, min_points=?, required_badge_count=?, required_badges_json=?, level_valid_days=?, sort_order=?, status=?, updated_at=NOW() WHERE id=?');
            $stmt->execute([$data['tier_name'],$data['tier_code'],$data['description'],$data['icon'],$data['color'],$data['min_points'],$data['required_badge_count'],$data['required_badges_json'],$data['level_valid_days'],$data['sort_order'],$data['status'],$id]);
            Security::audit((int)$user['id'], 'tier_updated', 'loyalty_tiers', $id, $data);
            Response::ok(['tier_id' => $id], 'Tier updated.');
        }
        $stmt = $pdo->prepare('INSERT INTO loyalty_tiers (tier_name,tier_code,description,icon,color,min_points,required_badge_count,required_badges_json,level_valid_days,sort_order,status,created_by,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,NOW(),NOW())');
        $stmt->execute([$data['tier_name'],$data['tier_code'],$data['description'],$data['icon'],$data['color'],$data['min_points'],$data['required_badge_count'],$data['required_badges_json'],$data['level_valid_days'],$data['sort_order'],$data['status'],(int)$user['id']]);
        $newId = (int)$pdo->lastInsertId();
        Security::audit((int)$user['id'], 'tier_created', 'loyalty_tiers', $newId, $data);
        Response::ok(['tier_id' => $newId], 'Tier created.');
    } catch (Throwable $e) {
        Response::error('Could not save tier: ' . $e->getMessage(), 500);
    }
}

if ($method === 'POST' && $action === 'save_sponsor') {
    Csrf::validateFromRequest();
    $data = pyrk_sponsor_input($input);
    $id = (int)($input['id'] ?? 0);
    try {
        if ($id > 0) {
            $stmt = $pdo->prepare('UPDATE reward_sponsors SET sponsor_name=?, contact_name=?, email=?, phone=?, website=?, logo_path=?, notes=?, status=?, updated_at=NOW() WHERE id=?');
            $stmt->execute([$data['sponsor_name'],$data['contact_name'],$data['email'],$data['phone'],$data['website'],$data['logo_path'],$data['notes'],$data['status'],$id]);
            Security::audit((int)$user['id'], 'sponsor_updated', 'reward_sponsors', $id, $data);
            Response::ok(['sponsor_id' => $id], 'Sponsor updated.');
        }
        $stmt = $pdo->prepare('INSERT INTO reward_sponsors (sponsor_name,contact_name,email,phone,website,logo_path,notes,status,created_by,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,NOW(),NOW())');
        $stmt->execute([$data['sponsor_name'],$data['contact_name'],$data['email'],$data['phone'],$data['website'],$data['logo_path'],$data['notes'],$data['status'],(int)$user['id']]);
        $newId = (int)$pdo->lastInsertId();
        Security::audit((int)$user['id'], 'sponsor_created', 'reward_sponsors', $newId, $data);
        Response::ok(['sponsor_id' => $newId], 'Sponsor created.');
    } catch (Throwable $e) {
        Response::error('Could not save sponsor: ' . $e->getMessage(), 500);
    }
}

if ($method === 'POST' && $action === 'save_reward_eligibility') {
    Csrf::validateFromRequest();
    $rewardId = (int)($input['reward_id'] ?? 0);
    if ($rewardId <= 0) Response::error('Prize is required.');
    $sponsorId = (int)($input['sponsor_id'] ?? 0);
    $from = trim((string)($input['available_from'] ?? '')) ?: null;
    $until = trim((string)($input['available_until'] ?? '')) ?: null;
    $tierIds = pyrk_tiers_ids($input['tier_ids'] ?? []);
    try {
        $pdo->beginTransaction();
        $pdo->prepare('UPDATE rewards SET sponsor_id=?, available_from=?, available_until=?, updated_at=NOW() WHERE id=?')->execute([$sponsorId ?: null, $from, $until, $rewardId]);
        $pdo->prepare('DELETE FROM reward_tier_eligibility WHERE reward_id=?')->execute([$rewardId]);
        if ($tierIds) {
            $ins = $pdo->prepare('INSERT IGNORE INTO reward_tier_eligibility (reward_id, tier_id, created_at) VALUES (?, ?, NOW())');
            foreach ($tierIds as $tid) $ins->execute([$rewardId, $tid]);
        }
        $pdo->commit();
        Security::audit((int)$user['id'], 'reward_tier_eligibility_saved', 'rewards', $rewardId, ['sponsor_id'=>$sponsorId, 'tier_ids'=>$tierIds]);
        Response::ok([], 'Prize sponsor and tier eligibility saved.');
    } catch (Throwable $e) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        Response::error('Could not save prize eligibility: ' . $e->getMessage(), 500);
    }
}

if ($method === 'POST' && $action === 'recalculate_member') {
    Csrf::validateFromRequest();
    $memberId = (int)($input['member_id'] ?? 0);
    if ($memberId <= 0) Response::error('Member is required.');
    $tier = TierService::recalculateMember($pdo, $memberId, (int)$user['id']);
    Response::ok(['tier' => $tier], $tier ? 'Member tier recalculated: ' . $tier['tier_name'] : 'Member does not qualify for an active tier.');
}

if ($method === 'POST' && $action === 'recalculate_all') {
    Csrf::validateFromRequest();
    $result = TierService::recalculateAll($pdo, (int)$user['id']);
    Security::audit((int)$user['id'], 'tiers_recalculated_all', 'loyalty_tiers', null, $result);
    Response::ok($result, 'Tiers recalculated for all active members.');
}

if ($method === 'POST' && $action === 'expire_now') {
    Csrf::validateFromRequest();
    $expired = TierService::expireOldTiers($pdo);
    Response::ok(['expired' => $expired], $expired . ' expired tier assignment(s) closed.');
}

Response::error('Unsupported tier action.', 404);
