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

use Zoo\Database;
use Zoo\Auth\PlayerAuthService;
use Zoo\Room\RoomManagerService;

function lz_setting(PDO $db,string $key,string $default): string {
    $q=$db->prepare("SELECT setting_value FROM bot_startup_settings WHERE setting_key=?");
    $q->execute([$key]);
    $v=$q->fetchColumn();
    return $v===false ? $default : (string)$v;
}

function lz_real_players(PDO $db,int $roomId): int {
    $q=$db->prepare("SELECT COUNT(*) FROM room_assignments WHERE room_id=? AND expires_at>NOW()");
    $q->execute([$roomId]);
    return max(0,(int)$q->fetchColumn());
}

function lz_ensure_bots(PDO $db,int $roomId,int $need): int {
    $q=$db->prepare("SELECT COUNT(*) FROM bot_startup_presence WHERE room_id=? AND active=1");
    $q->execute([$roomId]);
    $have=(int)$q->fetchColumn();

    // Retire excess immediately.
    if($have>$need){
        $n=$have-$need;
        $q=$db->prepare("
          SELECT bot_key FROM bot_startup_presence
          WHERE room_id=? AND active=1 ORDER BY id DESC LIMIT {$n}
        ");
        $q->execute([$roomId]);
        foreach($q->fetchAll(PDO::FETCH_COLUMN) as $key){
            $db->prepare("UPDATE bot_startup_presence SET active=0,last_seen_at=NOW() WHERE room_id=? AND bot_key=?")
               ->execute([$roomId,$key]);
            $db->prepare("UPDATE bot_simulated_wallets SET active=0,updated_at=NOW() WHERE room_id=? AND bot_key=?")
               ->execute([$roomId,$key]);
        }
        return $need;
    }

    $seedMin=max(1000,(int)lz_setting($db,'seed_min','5000'));
    $seedMax=max($seedMin,(int)lz_setting($db,'seed_max','25000'));

    for($i=$have;$i<$need;$i++){
        $key='B'.strtoupper(bin2hex(random_bytes(5)));
        $name='player'.random_int(100000,999999);
        $seed=(float)random_int($seedMin,$seedMax);

        $db->beginTransaction();
        try{
            $db->prepare("
              INSERT INTO bot_startup_presence
              (room_id,bot_key,display_name,active,activated_at,last_seen_at)
              VALUES (?,?,?,1,NOW(),NOW())
            ")->execute([$roomId,$key,$name]);

            $db->prepare("
              INSERT INTO bot_simulated_wallets
              (room_id,bot_key,simulated_balance,total_seeded,total_bet,total_won,
               active,last_activity_at,created_at,updated_at)
              VALUES (?,?,?, ?,0,0,1,NOW(),NOW(),NOW())
            ")->execute([$roomId,$key,$seed,$seed]);

            $db->prepare("
              INSERT INTO bot_simulated_funding_events
              (room_id,bot_key,event_type,amount,metadata,created_at)
              VALUES (?,?,'bot_seed_credit',?, ?,NOW())
            ")->execute([$roomId,$key,$seed,json_encode([
                'simulated'=>true,
                'counts_as_revenue'=>false,
                'counts_as_real_deposit'=>false,
                'purpose'=>'ui_startup_activity'
            ],JSON_UNESCAPED_SLASHES)]);

            $db->commit();
        }catch(Throwable $e){
            if($db->inTransaction())$db->rollBack();
            throw $e;
        }
    }
    return $need;
}

function lz_maybe_bot_bet(PDO $db,int $roomId,int $roundId,int $botCount,array $round,int $uiSeconds): int {
    if($botCount<=0 || lz_setting($db,'ui_bot_bets_enabled','1')!=='1') return 0;

    $fullRoomTarget=max(1000,(int)lz_setting($db,'ui_bot_target_amount_full_room','15000'));
    $roundTarget=(float)round($fullRoomTarget*($botCount/30),2);

    // Server-side hard safety gate.
    $q=$db->prepare("
      SELECT CASE
        WHEN state='BETTING_OPEN' AND closes_at>NOW(3) THEN 1 ELSE 0
      END
      FROM rounds
      WHERE id=? AND room_id=? LIMIT 1
    ");
    $q->execute([$roundId,$roomId]);
    if((int)$q->fetchColumn()!==1)return 0;

    $q=$db->prepare("SELECT COALESCE(SUM(amount),0) FROM bot_ui_bets WHERE round_id=?");
    $q->execute([$roundId]);
    $current=(float)$q->fetchColumn();
    $deficit=max(0,$roundTarget-$current);
    if($deficit<10)return 0;

    /*
     * Pace from the VISIBLE betting countdown, not server round age.
     * This avoids a huge first burst when the server next round opened while
     * the browser was still showing DRAWING/PRIZING.
     */
    $uiSeconds=max(1,min(60,$uiSeconds));
    $pollSeconds=0.85;
    $pollsLeft=max(1,(int)ceil($uiSeconds/$pollSeconds));

    // Slightly over-budget each poll so the target is reached before BETTING CLOSE.
    $budget=max(100.0,min($deficit,ceil(($deficit/$pollsLeft)*1.20/50)*50));

    // Keep many visible chip flights instead of one giant event.
    $maxEvents=$botCount>=20 ? 7 : ($botCount>=8 ? 5 : 3);
    $minEvents=$botCount>=20 ? 3 : ($botCount>=8 ? 2 : 1);

    $q=$db->prepare("
      SELECT p.bot_key,w.simulated_balance
      FROM bot_startup_presence p
      JOIN bot_simulated_wallets w
        ON w.room_id=p.room_id AND w.bot_key=p.bot_key
      WHERE p.room_id=? AND p.active=1 AND w.active=1
      ORDER BY RAND() LIMIT 12
    ");
    $q->execute([$roomId]);
    $bots=$q->fetchAll(PDO::FETCH_ASSOC);
    if(!$bots)return 0;

    $areas=[
      'rabbit','rabbit','panda','panda','monkey','monkey','lion','lion',
      'swallow','swallow','pigeon','pigeon','peacock','peacock','eagle','eagle',
      'bird_group','beast_group','shark','frog'
    ];

    $made=0;
    $spent=0.0;
    $eventGoal=min($maxEvents,max($minEvents,(int)ceil($budget/350)));

    for($i=0;$i<$eventGoal && $spent<$deficit;$i++){
        $bot=$bots[$i%count($bots)];
        $left=min($deficit-$spent,$budget-$spent);
        if($left<=0)break;

        // Choose a casino-like chip value close to the remaining per-event budget.
        $per=max(50,$left/max(1,$eventGoal-$i));
        if($per>=850)$amount=1000;
        elseif($per>=400)$amount=500;
        elseif($per>=160)$amount=200;
        elseif($per>=80)$amount=100;
        else $amount=50;

        $amount=(float)min($amount,$deficit-$spent);
        // Keep amounts on 10-unit increments.
        $amount=max(10,floor($amount/10)*10);

        $balance=(float)$bot['simulated_balance'];
        if($balance<2000){
            $reseed=(float)random_int(10000,30000);
            $db->beginTransaction();
            try{
                $db->prepare("
                  UPDATE bot_simulated_wallets
                  SET simulated_balance=simulated_balance+?,
                      total_seeded=total_seeded+?,
                      updated_at=NOW()
                  WHERE room_id=? AND bot_key=?
                ")->execute([$reseed,$reseed,$roomId,$bot['bot_key']]);

                $db->prepare("
                  INSERT INTO bot_simulated_funding_events
                  (room_id,bot_key,event_type,amount,metadata,created_at)
                  VALUES (?,?,'bot_reseed_credit',?, ?,NOW())
                ")->execute([$roomId,$bot['bot_key'],$reseed,json_encode([
                    'simulated'=>true,
                    'counts_as_revenue'=>false,
                    'purpose'=>'ui_startup_activity'
                ],JSON_UNESCAPED_SLASHES)]);
                $db->commit();
                $balance+=$reseed;
            }catch(Throwable $e){
                if($db->inTransaction())$db->rollBack();
                throw $e;
            }
        }
        if($balance<$amount)continue;

        $area=$areas[array_rand($areas)];

        $db->beginTransaction();
        try{
            $u=$db->prepare("
              UPDATE bot_simulated_wallets
              SET simulated_balance=simulated_balance-?,
                  total_bet=total_bet+?,
                  last_activity_at=NOW(),updated_at=NOW()
              WHERE room_id=? AND bot_key=? AND simulated_balance>=?
            ");
            $u->execute([$amount,$amount,$roomId,$bot['bot_key'],$amount]);
            if($u->rowCount()!==1){
                $db->rollBack();
                continue;
            }

            $db->prepare("
              INSERT INTO bot_ui_bets
              (round_id,room_id,bot_key,area,amount,created_at)
              VALUES (?,?,?,?,?,NOW(3))
            ")->execute([$roundId,$roomId,$bot['bot_key'],$area,$amount]);

            $db->commit();
            $made++;
            $spent+=$amount;
        }catch(Throwable $e){
            if($db->inTransaction())$db->rollBack();
            throw $e;
        }
    }

    return $made;
}

try{
    $db=Database::connect();
    $player=(new PlayerAuthService($db))->authenticate([]);
    $room=(new RoomManagerService($db))->assign((int)$player['user_id']);
    $roomId=(int)$room['room_id'];

    $q=$db->prepare("
      SELECT id,public_round_id,state,opened_at,closes_at
      FROM rounds
      WHERE room_id=? AND state='BETTING_OPEN' AND closes_at>NOW(3)
      ORDER BY id DESC LIMIT 1
    ");
    $q->execute([$roomId]);
    $round=$q->fetch(PDO::FETCH_ASSOC);
    if(!$round) json_out(['ok'=>false,'error'=>'No open betting round'],404);

    $real=lz_real_players($db,$roomId);
    $botTarget=max(0,30-$real);
    $bots=lz_ensure_bots($db,$roomId,$botTarget);

    $uiBetting=(string)($_GET['ui_betting'] ?? '')==='1';
    $uiSeconds=max(1,min(60,(int)($_GET['ui_seconds'] ?? 15)));
    $generated=$uiBetting
        ? lz_maybe_bot_bet($db,$roomId,(int)$round['id'],$bots,$round,$uiSeconds)
        : 0;

    $realTotals=[];
    $q=$db->prepare("SELECT area,SUM(amount) total FROM bets WHERE round_id=? GROUP BY area");
    $q->execute([(int)$round['id']]);
    foreach($q->fetchAll(PDO::FETCH_ASSOC) as $r)$realTotals[$r['area']]=(float)$r['total'];

    $botTotals=[];
    $q=$db->prepare("SELECT area,SUM(amount) total FROM bot_ui_bets WHERE round_id=? GROUP BY area");
    $q->execute([(int)$round['id']]);
    foreach($q->fetchAll(PDO::FETCH_ASSOC) as $r)$botTotals[$r['area']]=(float)$r['total'];

    $areas=['rabbit','panda','monkey','lion','swallow','pigeon','peacock','eagle','shark','frog','bird_group','beast_group'];
    $display=[];
    foreach($areas as $a)$display[$a]=round(($realTotals[$a]??0)+($botTotals[$a]??0),2);

    $after=max(0,(int)($_GET['after_id']??0));
    $q=$db->prepare("
      SELECT id,area,amount,created_at
      FROM bot_ui_bets WHERE round_id=? AND id>?
      ORDER BY id ASC LIMIT 30
    ");
    $q->execute([(int)$round['id'],$after]);
    $events=$q->fetchAll(PDO::FETCH_ASSOC);
    $lastId=$after;
    foreach($events as &$e){
        $e['id']=(int)$e['id'];
        $e['amount']=(float)$e['amount'];
        $lastId=max($lastId,$e['id']);
    }

    json_out([
      'ok'=>true,
      'room'=>[
        'id'=>$roomId,
        'visible_players'=>min(30,$real+$bots),
        'players_text'=>'👤 '.min(30,$real+$bots).' Players'
      ],
      'round'=>[
        'id'=>(int)$round['id'],
        'public_round_id'=>$round['public_round_id'],
        'state'=>$round['state']
      ],
      'display'=>[
        'candidate_totals'=>$display,
        'total_bet'=>round(array_sum($display),2)
      ],
      'bot_events'=>$events,
      'last_event_id'=>$lastId,
      'diagnostic'=>[
        'real_players'=>$real,
        'bot_players'=>$bots,
        'generated_this_poll'=>$generated,
        'real_bet_total'=>round(array_sum($realTotals),2),
        'bot_ui_bet_total'=>round(array_sum($botTotals),2),
        'bot_target_full_room'=>15000,
        'bot_target_this_round'=>round(15000*($bots/30),2),
        'ui_seconds'=>$uiSeconds
      ]
    ]);
}catch(Throwable $e){
    json_out([
      'ok'=>false,
      'error'=>$e->getMessage(),
      'file'=>basename($e->getFile()),
      'line'=>$e->getLine()
    ],422);
}
