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

use Zoo\Database;
use Zoo\Auth\PlayerAuthService;
use Zoo\Room\RoomManagerService;
use Zoo\Room\BotActivityService;
use Zoo\Game\RoundRuntimeService;

try {
    $db=Database::connect();
    $player=(new PlayerAuthService($db))->authenticate([]);

    $manager=new RoomManagerService($db);
    $room=$manager->assign((int)$player['user_id']);

    $freshRoundId=(new RoundRuntimeService($db))->tickRoom((int)$room['room_id'], true);

    $q=$db->prepare("
        SELECT id,public_round_id,room_id,state,opened_at,closes_at,server_seed_hash,
               GREATEST(
                   0,
                   TIMESTAMPDIFF(MICROSECOND,NOW(3),closes_at)/1000
               ) AS milliseconds_remaining
        FROM rounds
        WHERE room_id=?
        ORDER BY id DESC
        LIMIT 1
    ");
    $q->execute([$room['room_id']]);
    $round=$q->fetch();

    if(
        !$round
        || $round['state']!=='BETTING_OPEN'
        || (float)$round['milliseconds_remaining']<=0
    ){
        json_out(['ok'=>false,'error'=>'No open round right now','room'=>$room],404);
    }

    $round['milliseconds_remaining']=max(
        0,
        (int)round((float)$round['milliseconds_remaining'])
    );
    $round['seconds_remaining']=(int)ceil(
        $round['milliseconds_remaining']/1000
    );

    /*
     * UI-only fresh-round display value.
     * Authoritative betting still ends at closes_at.
     */
    $round['client_display_ms']=$round['milliseconds_remaining'];

    $bots=(new BotActivityService($db))->ensureForRound(
        (int)$room['room_id'],
        (int)$round['id']
    );

    /*
     * TRUE 13-SECOND BETTING START:
     * bot initialization happens first; only the request that created this
     * fresh round is allowed to start its authoritative 13-second clock.
     */
    if(
        $freshRoundId
        && (int)$freshRoundId===(int)$round['id']
        && $round['state']==='BETTING_OPEN'
    ){
        $q=$db->prepare("
            UPDATE rounds
            SET opened_at=NOW(3),
                closes_at=DATE_ADD(NOW(3),INTERVAL 13 SECOND)
            WHERE id=? AND state='BETTING_OPEN'
        ");
        $q->execute([(int)$round['id']]);

        $q=$db->prepare("
            SELECT id,public_round_id,room_id,state,opened_at,closes_at,server_seed_hash,
                   GREATEST(
                       0,
                       TIMESTAMPDIFF(MICROSECOND,NOW(3),closes_at)/1000
                   ) AS milliseconds_remaining
            FROM rounds
            WHERE id=?
            LIMIT 1
        ");
        $q->execute([(int)$round['id']]);
        $round=$q->fetch();

        $round['milliseconds_remaining']=max(
            0,
            (int)round((float)$round['milliseconds_remaining'])
        );
        $round['seconds_remaining']=(int)ceil(
            $round['milliseconds_remaining']/1000
        );
        $round['client_display_ms']=$round['milliseconds_remaining'];
    }

    $q=$db->prepare("
        SELECT COUNT(*) FROM room_assignments
        WHERE room_id=? AND expires_at>NOW()
    ");
    $q->execute([$room['room_id']]);
    $realPlayers=(int)$q->fetchColumn();

    /*
     * Continuous inactivity rule.
     *
     * 1-8 completed rounds with no REAL player bet: silent.
     * After 8 completed no-bet rounds: warning round #1.
     * After 9 completed no-bet rounds: warning round #2.
     * After 10 completed no-bet rounds: remove from current room.
     *
     * last_inactivity_round_id is a BIGINT tracker and prevents heartbeat
     * polling from counting the same settled round more than once.
     */
    $inactivity=[
        'inactive_rounds'=>0,
        'warning'=>false,
        'warning_step'=>0,
        'kicked'=>false
    ];

    /*
     * Existing/sticky room assignments may predate the inactivity feature.
     * Ensure they also have a room_sessions row.
     */
    $q=$db->prepare("
        SELECT id,room_id,inactive_rounds,warning_rounds,
               last_inactivity_round_id,kicked_at,joined_at
        FROM room_sessions
        WHERE user_id=? AND room_id=? AND kicked_at IS NULL
        ORDER BY id DESC
        LIMIT 1
    ");
    $q->execute([(int)$player['user_id'],(int)$room['room_id']]);
    $session=$q->fetch();

    if(!$session){
        $db->prepare("
            INSERT INTO room_sessions
              (room_id,user_id,inactive_rounds,warning_rounds,
               last_inactivity_round_id,kicked_at,joined_at,last_active_at)
            VALUES (?,?,0,0,NULL,NULL,NOW(),NOW())
        ")->execute([(int)$room['room_id'],(int)$player['user_id']]);

        $session=[
            'id'=>(int)$db->lastInsertId(),
            'room_id'=>(int)$room['room_id'],
            'inactive_rounds'=>0,
            'warning_rounds'=>0,
            'last_inactivity_round_id'=>null,
            'kicked_at'=>null,
            'joined_at'=>date('Y-m-d H:i:s')
        ];
    }

    if($session && !$session['kicked_at']){
        $currentRoundId=(int)$round['id'];
        $lastCounted=(int)($session['last_inactivity_round_id'] ?? 0);

        /*
         * Process ALL newly settled rounds since the last evaluation.
         * This keeps the counter correct even if a browser heartbeat is delayed.
         */
        $q=$db->prepare("
            SELECT id,opened_at,settled_at
            FROM rounds
            WHERE room_id=?
              AND id<?
              AND id>?
              AND state='SETTLED'
              AND settled_at IS NOT NULL
              AND opened_at>=?
            ORDER BY id ASC
        ");
        $q->execute([
            (int)$room['room_id'],
            $currentRoundId,
            $lastCounted,
            (string)$session['joined_at']
        ]);
        $newlySettled=$q->fetchAll();

        $inactive=(int)$session['inactive_rounds'];
        $warningRounds=(int)$session['warning_rounds'];
        $lastProcessed=$lastCounted;

        foreach($newlySettled as $finished){
            $finishedId=(int)$finished['id'];

            $q=$db->prepare("
                SELECT COUNT(*)
                FROM bets
                WHERE user_id=? AND round_id=?
                  AND status IN ('accepted','won','lost')
            ");
            $q->execute([(int)$player['user_id'],$finishedId]);
            $hadRealBet=(int)$q->fetchColumn()>0;

            if($hadRealBet){
                $inactive=0;
                $warningRounds=0;
            }else{
                $inactive++;
                $warningRounds=$inactive>=9 ? 2 : ($inactive>=8 ? 1 : 0);
            }

            $lastProcessed=$finishedId;
        }

        if($lastProcessed!==$lastCounted){
            $db->prepare("
                UPDATE room_sessions
                SET inactive_rounds=?,
                    warning_rounds=?,
                    last_inactivity_round_id=?,
                    last_active_at=CASE WHEN ?=0 THEN NOW() ELSE last_active_at END
                WHERE id=? AND kicked_at IS NULL
            ")->execute([
                $inactive,
                $warningRounds,
                $lastProcessed,
                $inactive,
                (int)$session['id']
            ]);
        }

        if($inactive>=10){
            $db->prepare("
                UPDATE room_sessions
                SET kicked_at=NOW()
                WHERE id=? AND kicked_at IS NULL
            ")->execute([(int)$session['id']]);

            // Remove only room membership. Login/guest authentication stays alive.
            $db->prepare("DELETE FROM room_assignments WHERE user_id=?")
               ->execute([(int)$player['user_id']]);

            $inactivity=[
                'inactive_rounds'=>$inactive,
                'warning'=>false,
                'warning_step'=>0,
                'kicked'=>true
            ];
        }else{
            $warningStep=$inactive===8 ? 1 : ($inactive===9 ? 2 : 0);

            $inactivity=[
                'inactive_rounds'=>$inactive,
                'warning'=>$warningStep>0,
                'warning_step'=>$warningStep,
                'kicked'=>false
            ];
        }
    }

    json_out([
        'ok'=>true,
        'player'=>[
            'user_id'=>(int)$player['user_id'],
            'public_id'=>$player['public_id'],
            'account_type'=>$player['account_type'],
            'auth_mode'=>$player['auth_mode']
        ],
        'room'=>[
            'id'=>(int)$room['room_id'],
            'code'=>$room['code'],
            'name'=>$room['name'],
            'capacity'=>(int)$room['capacity'],
            'real_players'=>$realPlayers,
            'sticky'=>$room['sticky']
        ],
        'round'=>$round,
        'bots'=>$bots,
        'inactivity'=>$inactivity
    ]);
} catch(Throwable $e) {
    json_out(['ok'=>false,'error'=>$e->getMessage()],401);
}
