<?php

declare(strict_types=1);

require_once __DIR__ . '/bootstrap.php';
require_once __DIR__ . '/admin_auth_lib.php';
require_once __DIR__ . '/db.php';
require_once __DIR__ . '/ticket_lib.php';

mocker_admin_require_permission('events');

$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';

try {
    $pdo = mocker_db();
} catch (Throwable $e) {
    http_response_code(503);
    echo json_encode(['ok' => false, 'error' => 'db'], JSON_UNESCAPED_UNICODE);
    exit;
}

if ($method === 'GET') {
    $detailEventId = isset($_GET['eventId']) ? (int) $_GET['eventId'] : 0;
    if ($detailEventId > 0) {
        $st = $pdo->prepare(
            'SELECT e.*,
                    (SELECT COUNT(DISTINCT user_id) FROM ticket_entries t WHERE t.event_id = e.id) AS participant_count,
                    (SELECT COUNT(*) FROM ticket_entries t WHERE t.event_id = e.id) AS entry_count,
                    (SELECT COUNT(*) FROM ticket_entries t WHERE t.event_id = e.id AND t.is_winner = 1) AS winner_marked,
                    (SELECT COALESCE(SUM(investment_amount), 0) FROM ticket_requests r WHERE r.event_id = e.id AND r.status != \'rejected\') AS total_investment
             FROM ticket_events e
             WHERE e.id = :id AND e.category = \'campaign\'
             LIMIT 1'
        );
        $st->execute([':id' => $detailEventId]);
        $r = $st->fetch(PDO::FETCH_ASSOC);
        if (!$r) {
            http_response_code(404);
            echo json_encode(['ok' => false, 'error' => 'not_found'], JSON_UNESCAPED_UNICODE);
            exit;
        }
        $winners = [];
        if ((string) $r['status'] === 'drawn') {
            $wSt = $pdo->prepare(
                'SELECT t.ticket_code, t.user_id, u.username
                 FROM ticket_entries t
                 INNER JOIN users u ON u.id = t.user_id
                 WHERE t.event_id = :eid AND t.is_winner = 1
                 ORDER BY t.id ASC'
            );
            $wSt->execute([':eid' => $detailEventId]);
            foreach ($wSt->fetchAll(PDO::FETCH_ASSOC) as $w) {
                $winners[] = [
                    'username' => (string) $w['username'],
                    'ticketCode' => (string) $w['ticket_code'],
                    'userId' => (int) $w['user_id'],
                ];
            }
        }
        $reqSt = $pdo->prepare(
            'SELECT r.* FROM ticket_requests r WHERE r.event_id = :eid ORDER BY r.created_at DESC LIMIT 500'
        );
        $reqSt->execute([':eid' => $detailEventId]);
        $requests = [];
        foreach ($reqSt->fetchAll(PDO::FETCH_ASSOC) as $rq) {
            $requests[] = [
                'id' => (int) $rq['id'],
                'userId' => (int) $rq['user_id'],
                'username' => (string) $rq['username'],
                'siteUsername' => (string) $rq['site_username'],
                'investmentAmount' => (float) $rq['investment_amount'],
                'investmentAt' => $rq['investment_at'] !== null ? (int) $rq['investment_at'] : null,
                'ticketRef' => (string) $rq['ticket_ref'],
                'ticketsEligible' => (int) $rq['tickets_eligible'],
                'ticketsGranted' => (int) $rq['tickets_granted'],
                'status' => (string) $rq['status'],
                'adminNote' => (string) $rq['admin_note'],
                'createdAt' => (int) $rq['created_at'],
                'reviewedAt' => $rq['reviewed_at'] !== null ? (int) $rq['reviewed_at'] : null,
            ];
        }
        $entSt = $pdo->prepare(
            'SELECT t.id, t.user_id, t.ticket_code, t.is_winner, t.created_at, u.username
             FROM ticket_entries t
             INNER JOIN users u ON u.id = t.user_id
             WHERE t.event_id = :eid
             ORDER BY t.created_at DESC
             LIMIT 500'
        );
        $entSt->execute([':eid' => $detailEventId]);
        $entries = [];
        foreach ($entSt->fetchAll(PDO::FETCH_ASSOC) as $en) {
            $entries[] = [
                'id' => (int) $en['id'],
                'userId' => (int) $en['user_id'],
                'username' => (string) $en['username'],
                'ticketCode' => (string) $en['ticket_code'],
                'isWinner' => (int) $en['is_winner'] === 1,
                'createdAt' => (int) $en['created_at'],
            ];
        }
        $pendingCount = 0;
        foreach ($requests as $rq) {
            if ($rq['status'] === 'pending') {
                $pendingCount++;
            }
        }
        echo json_encode(
            [
                'ok' => true,
                'event' => [
                    'id' => $detailEventId,
                    'title' => (string) $r['title'],
                    'description' => (string) $r['description'],
                    'sponsorId' => (string) ($r['sponsor_id'] ?? ''),
                    'sponsorTitle' => (string) $r['sponsor_title'],
                    'logoUrl' => (string) $r['logo_url'],
                    'siteUrl' => (string) $r['site_url'],
                    'prizeDescription' => (string) $r['prize_description'],
                    'winnerCount' => (int) $r['winner_count'],
                    'ticketCost' => (int) $r['ticket_cost'],
                    'maxEntriesPerUser' => (int) $r['max_entries_per_user'],
                    'maxTotalTickets' => (int) ($r['max_total_tickets'] ?? 0),
                    'investmentPerTicket' => (float) ($r['investment_per_ticket'] ?? 1000),
                    'status' => (string) $r['status'],
                    'endsAt' => $r['ends_at'] !== null ? (int) $r['ends_at'] : null,
                    'createdAt' => (int) $r['created_at'],
                    'drawnAt' => $r['drawn_at'] !== null ? (int) $r['drawn_at'] : null,
                    'participantCount' => (int) $r['participant_count'],
                    'entryCount' => (int) $r['entry_count'],
                    'winnerMarked' => (int) $r['winner_marked'],
                    'totalInvestment' => (float) $r['total_investment'],
                    'pendingRequests' => $pendingCount,
                    'winners' => $winners,
                ],
                'requests' => $requests,
                'entries' => $entries,
            ],
            JSON_UNESCAPED_UNICODE
        );
        exit;
    }

    $st = $pdo->query(
        'SELECT e.*,
                (SELECT COUNT(*) FROM ticket_entries t WHERE t.event_id = e.id) AS entry_count,
                (SELECT COUNT(DISTINCT user_id) FROM ticket_entries t WHERE t.event_id = e.id) AS participant_count,
                (SELECT COUNT(*) FROM ticket_requests r WHERE r.event_id = e.id AND r.status = \'pending\') AS pending_requests,
                (SELECT COUNT(*) FROM ticket_entries t WHERE t.event_id = e.id AND t.is_winner = 1) AS winner_marked
         FROM ticket_events e
         WHERE e.category = \'campaign\'
         ORDER BY e.created_at DESC
         LIMIT 100'
    );
    $events = [];
    foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $r) {
        $eid = (int) $r['id'];
        $winners = [];
        if ((string) $r['status'] === 'drawn') {
            $wSt = $pdo->prepare(
                'SELECT t.ticket_code, t.user_id, u.username
                 FROM ticket_entries t
                 INNER JOIN users u ON u.id = t.user_id
                 WHERE t.event_id = :eid AND t.is_winner = 1
                 ORDER BY t.id ASC'
            );
            $wSt->execute([':eid' => $eid]);
            foreach ($wSt->fetchAll(PDO::FETCH_ASSOC) as $w) {
                $winners[] = [
                    'username' => (string) $w['username'],
                    'ticketCode' => (string) $w['ticket_code'],
                    'userId' => (int) $w['user_id'],
                ];
            }
        }
        $events[] = [
            'id' => $eid,
            'title' => (string) $r['title'],
            'description' => (string) $r['description'],
            'sponsorId' => (string) ($r['sponsor_id'] ?? ''),
            'sponsorTitle' => (string) $r['sponsor_title'],
            'logoUrl' => (string) $r['logo_url'],
            'siteUrl' => (string) $r['site_url'],
            'prizeDescription' => (string) $r['prize_description'],
            'winnerCount' => (int) $r['winner_count'],
            'ticketCost' => (int) $r['ticket_cost'],
            'maxEntriesPerUser' => (int) $r['max_entries_per_user'],
            'status' => (string) $r['status'],
            'endsAt' => $r['ends_at'] !== null ? (int) $r['ends_at'] : null,
            'createdAt' => (int) $r['created_at'],
            'drawnAt' => $r['drawn_at'] !== null ? (int) $r['drawn_at'] : null,
            'entryCount' => (int) $r['entry_count'],
            'participantCount' => (int) ($r['participant_count'] ?? 0),
            'pendingRequests' => (int) ($r['pending_requests'] ?? 0),
            'maxTotalTickets' => (int) ($r['max_total_tickets'] ?? 0),
            'investmentPerTicket' => (float) ($r['investment_per_ticket'] ?? 1000),
            'winnerMarked' => (int) $r['winner_marked'],
            'winners' => $winners,
        ];
    }
    echo json_encode(['ok' => true, 'events' => $events, 'sponsors' => mocker_sponsors_admin_options()], JSON_UNESCAPED_UNICODE);
    exit;
}

if ($method !== 'POST') {
    http_response_code(405);
    echo json_encode(['ok' => false, 'error' => 'method'], JSON_UNESCAPED_UNICODE);
    exit;
}

mocker_require_csrf_post();

$input = json_decode((string) file_get_contents('php://input'), true) ?: [];
$action = (string) ($input['action'] ?? '');

if ($action === 'create') {
    $title = trim((string) ($input['title'] ?? ''));
    if ($title === '') {
        http_response_code(400);
        echo json_encode(['ok' => false, 'error' => 'title'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    $endsAt = null;
    if (!empty($input['endsAt'])) {
        $endsAt = (int) $input['endsAt'];
        if ($endsAt <= 0) {
            $endsAt = null;
        }
    }
    $resolved = mocker_ticket_resolve_sponsor_fields($input);
    $pdo->prepare(
        'INSERT INTO ticket_events (
            title, description, sponsor_id, sponsor_title, logo_url, site_url, prize_description,
            winner_count, ticket_cost, max_entries_per_user, max_total_tickets, investment_per_ticket,
            status, ends_at, created_at, category
        ) VALUES (
            :title, :desc, :sid, :sponsor, :logo, :site, :prize,
            :wc, :cost, :maxu, :cap, :perinv,
            \'open\', :ends, :created, \'campaign\'
        )'
    )->execute([
        ':title' => mocker_utf8_substr($title, 0, 120),
        ':desc' => mocker_utf8_substr(trim((string) ($input['description'] ?? '')), 0, 2000),
        ':sid' => mocker_utf8_substr($resolved['sponsorId'], 0, 64),
        ':sponsor' => mocker_utf8_substr($resolved['sponsorTitle'], 0, 120),
        ':logo' => mocker_utf8_substr(trim((string) ($input['logoUrl'] ?? '')), 0, 500),
        ':site' => mocker_utf8_substr($resolved['siteUrl'], 0, 500),
        ':prize' => mocker_utf8_substr(trim((string) ($input['prizeDescription'] ?? '')), 0, 500),
        ':wc' => max(1, min(500, (int) ($input['winnerCount'] ?? 1))),
        ':cost' => max(0, min(999999, (int) ($input['ticketCost'] ?? 0))),
        ':maxu' => max(1, min(100, (int) ($input['maxEntriesPerUser'] ?? 20))),
        ':cap' => max(0, min(999999, (int) ($input['maxTotalTickets'] ?? 0))),
        ':perinv' => max(1, min(99999999, (float) ($input['investmentPerTicket'] ?? 1000))),
        ':ends' => $endsAt,
        ':created' => time(),
    ]);
    echo json_encode(['ok' => true, 'id' => (int) $pdo->lastInsertId()], JSON_UNESCAPED_UNICODE);
    exit;
}

$eventId = (int) ($input['eventId'] ?? 0);
if ($eventId <= 0 && !in_array($action, ['create', 'approve_request', 'reject_request'], true)) {
    http_response_code(400);
    echo json_encode(['ok' => false, 'error' => 'event'], JSON_UNESCAPED_UNICODE);
    exit;
}

if ($action === 'approve_request') {
    $requestId = (int) ($input['requestId'] ?? 0);
    if ($requestId <= 0) {
        http_response_code(400);
        echo json_encode(['ok' => false, 'error' => 'request'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    $override = isset($input['ticketCount']) ? (int) $input['ticketCount'] : null;
    $result = mocker_ticket_grant_entries_for_request($pdo, $requestId, $override);
    if (!$result['ok']) {
        http_response_code(400);
        echo json_encode(['ok' => false, 'error' => $result['error'] ?? 'fail'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    echo json_encode(
        ['ok' => true, 'granted' => $result['granted'], 'codes' => $result['codes'] ?? []],
        JSON_UNESCAPED_UNICODE
    );
    exit;
}

if ($action === 'reject_request') {
    $requestId = (int) ($input['requestId'] ?? 0);
    if ($requestId <= 0) {
        http_response_code(400);
        echo json_encode(['ok' => false, 'error' => 'request'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    $note = mocker_utf8_substr(trim((string) ($input['adminNote'] ?? '')), 0, 500);
    $st = $pdo->prepare('SELECT status FROM ticket_requests WHERE id = :id LIMIT 1');
    $st->execute([':id' => $requestId]);
    $cur = $st->fetch(PDO::FETCH_ASSOC);
    if (!$cur) {
        http_response_code(404);
        echo json_encode(['ok' => false, 'error' => 'not_found'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    if ((string) $cur['status'] !== 'pending') {
        http_response_code(400);
        echo json_encode(['ok' => false, 'error' => 'not_pending'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    $pdo->prepare(
        'UPDATE ticket_requests SET status = \'rejected\', admin_note = :n, reviewed_at = :t WHERE id = :id'
    )->execute([':n' => $note, ':t' => time(), ':id' => $requestId]);
    echo json_encode(['ok' => true], JSON_UNESCAPED_UNICODE);
    exit;
}

if ($action === 'manual_request') {
    if ($eventId <= 0) {
        http_response_code(400);
        echo json_encode(['ok' => false, 'error' => 'event'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    $userId = (int) ($input['userId'] ?? 0);
    $siteUsername = trim((string) ($input['siteUsername'] ?? ''));
    $investmentAmount = (float) ($input['investmentAmount'] ?? 0);
    $autoApprove = !empty($input['autoApprove']);
    if ($userId <= 0 || $siteUsername === '' || $investmentAmount <= 0) {
        http_response_code(400);
        echo json_encode(['ok' => false, 'error' => 'fields'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    $evSt = $pdo->prepare('SELECT investment_per_ticket, status FROM ticket_events WHERE id = :id');
    $evSt->execute([':id' => $eventId]);
    $ev = $evSt->fetch(PDO::FETCH_ASSOC);
    if (!$ev || (string) $ev['status'] === 'drawn') {
        http_response_code(400);
        echo json_encode(['ok' => false, 'error' => 'event'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    $userSt = $pdo->prepare('SELECT username FROM users WHERE id = :id');
    $userSt->execute([':id' => $userId]);
    $u = $userSt->fetch(PDO::FETCH_ASSOC);
    if (!$u) {
        http_response_code(404);
        echo json_encode(['ok' => false, 'error' => 'user'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    $invAt = time();
    if (!empty($input['investmentAt'])) {
        $invAt = (int) $input['investmentAt'];
    }
    $eligible = isset($input['ticketsEligible'])
        ? max(1, (int) $input['ticketsEligible'])
        : mocker_ticket_calc_eligible($investmentAmount, (float) ($ev['investment_per_ticket'] ?? 1000));
    $now = time();
    $pdo->prepare(
        'INSERT INTO ticket_requests (
            event_id, user_id, username, site_username, investment_amount, investment_at,
            ticket_ref, tickets_eligible, tickets_granted, status, admin_note, created_at
        ) VALUES (
            :eid, :uid, :un, :site, :amt, :inv, \'\', :elig, 0, \'pending\', :note, :t
        )'
    )->execute([
        ':eid' => $eventId,
        ':uid' => $userId,
        ':un' => mocker_utf8_substr(trim((string) $u['username']), 0, 80),
        ':site' => mocker_utf8_substr($siteUsername, 0, 120),
        ':amt' => round($investmentAmount, 2),
        ':inv' => $invAt,
        ':elig' => $eligible,
        ':note' => mocker_utf8_substr(trim((string) ($input['adminNote'] ?? 'Manuel')), 0, 500),
        ':t' => $now,
    ]);
    $newId = (int) $pdo->lastInsertId();
    $granted = 0;
    $codes = [];
    if ($autoApprove) {
        $result = mocker_ticket_grant_entries_for_request($pdo, $newId, $eligible);
        if ($result['ok']) {
            $granted = (int) ($result['granted'] ?? 0);
            $codes = $result['codes'] ?? [];
        }
    }
    echo json_encode(['ok' => true, 'id' => $newId, 'granted' => $granted, 'codes' => $codes], JSON_UNESCAPED_UNICODE);
    exit;
}

if ($action === 'update') {
    $st = $pdo->prepare('SELECT status FROM ticket_events WHERE id = :id LIMIT 1');
    $st->execute([':id' => $eventId]);
    $cur = $st->fetch(PDO::FETCH_ASSOC);
    if (!$cur) {
        http_response_code(404);
        echo json_encode(['ok' => false, 'error' => 'not_found'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    if ((string) $cur['status'] === 'drawn') {
        http_response_code(400);
        echo json_encode(['ok' => false, 'error' => 'drawn'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    $endsAt = null;
    if (array_key_exists('endsAt', $input)) {
        $endsAt = $input['endsAt'] === null || $input['endsAt'] === '' ? null : (int) $input['endsAt'];
        if ($endsAt !== null && $endsAt <= 0) {
            $endsAt = null;
        }
    } else {
        $eSt = $pdo->prepare('SELECT ends_at FROM ticket_events WHERE id = :id');
        $eSt->execute([':id' => $eventId]);
        $row = $eSt->fetch(PDO::FETCH_ASSOC);
        $endsAt = $row && $row['ends_at'] !== null ? (int) $row['ends_at'] : null;
    }
    $resolved = mocker_ticket_resolve_sponsor_fields($input);
    $pdo->prepare(
        'UPDATE ticket_events SET
            title = :title,
            description = :desc,
            sponsor_id = :sid,
            sponsor_title = :sponsor,
            logo_url = :logo,
            site_url = :site,
            prize_description = :prize,
            winner_count = :wc,
            ticket_cost = :cost,
            max_entries_per_user = :maxu,
            max_total_tickets = :cap,
            investment_per_ticket = :perinv,
            ends_at = :ends
         WHERE id = :id AND category = \'campaign\''
    )->execute([
        ':title' => mocker_utf8_substr(trim((string) ($input['title'] ?? '')), 0, 120),
        ':desc' => mocker_utf8_substr(trim((string) ($input['description'] ?? '')), 0, 2000),
        ':sid' => mocker_utf8_substr($resolved['sponsorId'], 0, 64),
        ':sponsor' => mocker_utf8_substr($resolved['sponsorTitle'], 0, 120),
        ':logo' => mocker_utf8_substr(trim((string) ($input['logoUrl'] ?? '')), 0, 500),
        ':site' => mocker_utf8_substr($resolved['siteUrl'], 0, 500),
        ':prize' => mocker_utf8_substr(trim((string) ($input['prizeDescription'] ?? '')), 0, 500),
        ':wc' => max(1, min(500, (int) ($input['winnerCount'] ?? 1))),
        ':cost' => max(0, min(999999, (int) ($input['ticketCost'] ?? 0))),
        ':maxu' => max(1, min(100, (int) ($input['maxEntriesPerUser'] ?? 20))),
        ':cap' => max(0, min(999999, (int) ($input['maxTotalTickets'] ?? 0))),
        ':perinv' => max(1, min(99999999, (float) ($input['investmentPerTicket'] ?? 1000))),
        ':ends' => $endsAt,
        ':id' => $eventId,
    ]);
    echo json_encode(['ok' => true], JSON_UNESCAPED_UNICODE);
    exit;
}

if ($action === 'save_cover') {
    $st = $pdo->prepare('SELECT status FROM ticket_events WHERE id = :id LIMIT 1');
    $st->execute([':id' => $eventId]);
    $cur = $st->fetch(PDO::FETCH_ASSOC);
    if (!$cur) {
        http_response_code(404);
        echo json_encode(['ok' => false, 'error' => 'not_found'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    if ((string) $cur['status'] === 'drawn') {
        http_response_code(400);
        echo json_encode(['ok' => false, 'error' => 'drawn'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    $logo = mocker_utf8_substr(trim((string) ($input['logoUrl'] ?? '')), 0, 500);
    $pdo->prepare('UPDATE ticket_events SET logo_url = :logo WHERE id = :id')->execute([
        ':logo' => $logo,
        ':id' => $eventId,
    ]);
    echo json_encode(['ok' => true, 'logoUrl' => $logo], JSON_UNESCAPED_UNICODE);
    exit;
}

if ($action === 'set_status') {
    $status = (string) ($input['status'] ?? '');
    if (!in_array($status, ['open', 'closed'], true)) {
        http_response_code(400);
        echo json_encode(['ok' => false, 'error' => 'status'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    $st = $pdo->prepare('SELECT status FROM ticket_events WHERE id = :id LIMIT 1');
    $st->execute([':id' => $eventId]);
    $cur = $st->fetch(PDO::FETCH_ASSOC);
    if (!$cur) {
        http_response_code(404);
        echo json_encode(['ok' => false, 'error' => 'not_found'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    if ((string) $cur['status'] === 'drawn') {
        http_response_code(400);
        echo json_encode(['ok' => false, 'error' => 'drawn'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    $pdo->prepare('UPDATE ticket_events SET status = :s WHERE id = :id')->execute([':s' => $status, ':id' => $eventId]);
    echo json_encode(['ok' => true], JSON_UNESCAPED_UNICODE);
    exit;
}

if ($action === 'draw') {
    $want = isset($input['winnerCount']) ? (int) $input['winnerCount'] : 0;
    $result = mocker_ticket_draw_winners($pdo, $eventId, $want);
    if (!$result['ok']) {
        $code = $result['error'] ?? 'fail';
        $status = $code === 'not_found' ? 404 : 400;
        http_response_code($status);
        echo json_encode(['ok' => false, 'error' => $code], JSON_UNESCAPED_UNICODE);
        exit;
    }
    echo json_encode(
        [
            'ok' => true,
            'winners' => $result['winners'],
            'winnerCount' => $result['winnerCount'],
        ],
        JSON_UNESCAPED_UNICODE
    );
    exit;
}

if ($action === 'delete') {
    $result = mocker_ticket_delete_event($pdo, $eventId);
    if (!$result['ok']) {
        $code = $result['error'] ?? 'fail';
        http_response_code($code === 'not_found' ? 404 : 400);
        echo json_encode(['ok' => false, 'error' => $code], JSON_UNESCAPED_UNICODE);
        exit;
    }
    echo json_encode(['ok' => true], JSON_UNESCAPED_UNICODE);
    exit;
}

http_response_code(400);
echo json_encode(['ok' => false, 'error' => 'action'], JSON_UNESCAPED_UNICODE);
