<?php

namespace App\Services;

use App\Models\Round;
use App\Models\Withdrawal;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

class PlatformMetricsService
{
    public function snapshot(?string $city = null, ?string $state = null): array
    {
        $city = $this->normalizeCity($city);
        $state = $this->normalizeState($state);

        if (! Schema::hasTable('rounds') || ! Schema::hasTable('withdrawals')) {
            return $this->fallbackSnapshot($city, $state);
        }

        $now = now();
        $todayStart = $now->copy()->startOfDay();
        $monthStart = $now->copy()->startOfMonth();

        $arrecadadoHoje = $this->sumRevenueSince($todayStart, $city, $state);
        $arrecadadoMes = $this->sumRevenueSince($monthStart, $city, $state);
        $arrecadadoTotal = $this->sumRevenueSince(null, $city, $state);

        $premiosQuery = Round::query()
            ->where('status', 'closed')
            ->selectRaw('COALESCE(SUM(prize_total), 0) as total');

        $this->applyLocationFilter($premiosQuery, $city, $state);
        $premiosPagos = (float) $premiosQuery->value('total');

        $saquesPagos = (float) Withdrawal::query()
            ->where('status', 'paid')
            ->sum('amount');

        $lucroLiquido = $arrecadadoTotal - $premiosPagos - $saquesPagos;

        $openRoundsQuery = Round::query()->where('status', 'open');
        $this->applyLocationFilter($openRoundsQuery, $city, $state);
        $rodadasAbertas = (int) $openRoundsQuery->count();

        $closedRoundsQuery = Round::query()->where('status', 'closed');
        $this->applyLocationFilter($closedRoundsQuery, $city, $state);
        $rodadasEncerradas = (int) $closedRoundsQuery->count();

        $nextRoundQuery = Round::query()
            ->where('status', 'open')
            ->orderBy('starts_at');
        $this->applyLocationFilter($nextRoundQuery, $city, $state);
        $nextRound = $nextRoundQuery->first();

        $nextRoundAt = $nextRound?->starts_at ?? $now->copy()->addMinutes(20);
        $entryPrice = (float) ($nextRound?->entry_price ?? 5);

        $onlineSessions = $this->countActiveSessions($city, $state);

        $entriesQuery = Round::query()
            ->where('status', 'open')
            ->selectRaw('COALESCE(SUM(total_entries), 0) as total');
        $this->applyLocationFilter($entriesQuery, $city, $state);
        $entriesInOpenRounds = (int) $entriesQuery->value('total');

        // Preferimos participantes das rodadas abertas para manter coerência com o cálculo do prêmio.
        $jogadoresOnline = $entriesInOpenRounds > 0 ? $entriesInOpenRounds : $onlineSessions;

        $estimatedPrize = (float) ($nextRound?->prize_total ?? 42000);

        if ($jogadoresOnline > 0) {
            $grossAmount = $jogadoresOnline * $entryPrice;
            $contextState = $state ?? $nextRound?->state;
            $contextCity = $city ?? $nextRound?->city;

            $estimatedPrize = (new CityPayoutService())->calculatePrizeAmount(
                $grossAmount,
                $contextState,
                $contextCity
            );
        }

        $cityContext = $city && $state ? $city . '/' . $state : ($city ?? 'Todas as cidades');

        return [
            'adminStats' => [
                ['key' => 'today', 'label' => 'Total arrecadado hoje', 'value' => $this->formatBrl($arrecadadoHoje)],
                ['key' => 'month', 'label' => 'Total arrecadado no mês', 'value' => $this->formatBrl($arrecadadoMes)],
                ['key' => 'prizes', 'label' => 'Total pago em prêmios', 'value' => $this->formatBrl($premiosPagos)],
                ['key' => 'withdrawals', 'label' => 'Total pago em saques', 'value' => $this->formatBrl($saquesPagos)],
                ['key' => 'profit', 'label' => 'Lucro líquido', 'value' => $this->formatBrl($lucroLiquido)],
                ['key' => 'online', 'label' => 'Jogadores online', 'value' => number_format($jogadoresOnline, 0, ',', '.')],
                ['key' => 'open_rounds', 'label' => 'Rodadas abertas', 'value' => (string) $rodadasAbertas],
                ['key' => 'closed_rounds', 'label' => 'Rodadas encerradas', 'value' => (string) $rodadasEncerradas],
            ],
            'lobby' => [
                'next_round_at' => $nextRoundAt->toIso8601String(),
                'next_round_label' => $this->formatNextRoundLabel($nextRoundAt),
                'countdown' => $this->formatCountdown($nextRoundAt),
                'players_online' => $jogadoresOnline,
                'players_online_formatted' => number_format($jogadoresOnline, 0, ',', '.'),
                'estimated_prize' => $estimatedPrize,
                'estimated_prize_brl' => $this->formatBrl($estimatedPrize),
                'entry_price' => $entryPrice,
                'entry_price_brl' => $this->formatBrl($entryPrice),
                'rounds_open' => $rodadasAbertas,
                'city' => $cityContext,
            ],
        ];
    }

    private function sumRevenueSince($from, ?string $city = null, ?string $state = null): float
    {
        $query = Round::query()->selectRaw('COALESCE(SUM(total_entries * entry_price), 0) as total');

        $this->applyLocationFilter($query, $city, $state);

        if ($from !== null) {
            $query->where('created_at', '>=', $from);
        }

        return (float) $query->value('total');
    }

    private function countActiveSessions(?string $city = null, ?string $state = null): int
    {
        if (! Schema::hasTable('sessions')) {
            return 0;
        }

        $threshold = now()->subMinutes(5)->getTimestamp();

        $query = DB::table('sessions')
            ->where('last_activity', '>=', $threshold);

        if (($city !== null || $state !== null) && Schema::hasTable('users')) {
            $query->join('users', 'users.id', '=', 'sessions.user_id')
                ->whereNotNull('sessions.user_id');

            if ($city !== null) {
                $query->where('users.city', $city);
            }

            if ($state !== null && Schema::hasColumn('users', 'state')) {
                $query->where('users.state', $state);
            }
        }

        return (int) $query->count();
    }

    private function formatBrl(float $amount): string
    {
        return 'R$ ' . number_format($amount, 2, ',', '.');
    }

    private function formatNextRoundLabel($nextRoundAt): string
    {
        if ($nextRoundAt->isSameDay(now())) {
            return 'Hoje às ' . $nextRoundAt->format('H:i');
        }

        return $nextRoundAt->format('d/m') . ' às ' . $nextRoundAt->format('H:i');
    }

    private function formatCountdown($nextRoundAt): string
    {
        $seconds = max(0, now()->diffInSeconds($nextRoundAt, false));
        $hours = intdiv($seconds, 3600);
        $minutes = intdiv($seconds % 3600, 60);
        $remainingSeconds = $seconds % 60;

        return sprintf('%02d:%02d:%02d', $hours, $minutes, $remainingSeconds);
    }

    private function fallbackSnapshot(?string $city = null, ?string $state = null): array
    {
        $nextRoundAt = now()->addMinutes(18);
        $cityContext = $city && $state ? $city . '/' . $state : ($city ?? 'Todas as cidades');

        return [
            'adminStats' => [
                ['key' => 'today', 'label' => 'Total arrecadado hoje', 'value' => 'R$ 18.740,00'],
                ['key' => 'month', 'label' => 'Total arrecadado no mês', 'value' => 'R$ 462.380,00'],
                ['key' => 'prizes', 'label' => 'Total pago em prêmios', 'value' => 'R$ 221.900,00'],
                ['key' => 'withdrawals', 'label' => 'Total pago em saques', 'value' => 'R$ 96.320,00'],
                ['key' => 'profit', 'label' => 'Lucro líquido', 'value' => 'R$ 144.160,00'],
                ['key' => 'online', 'label' => 'Jogadores online', 'value' => '1.286'],
                ['key' => 'open_rounds', 'label' => 'Rodadas abertas', 'value' => '12'],
                ['key' => 'closed_rounds', 'label' => 'Rodadas encerradas', 'value' => '140'],
            ],
            'lobby' => [
                'next_round_at' => $nextRoundAt->toIso8601String(),
                'next_round_label' => 'Hoje às 20:00',
                'countdown' => '00:18:27',
                'players_online' => 1286,
                'players_online_formatted' => '1.286',
                'estimated_prize' => 42000,
                'estimated_prize_brl' => 'R$ 42.000,00',
                'entry_price' => 5,
                'entry_price_brl' => 'R$ 5,00',
                'rounds_open' => 12,
                'city' => $cityContext,
            ],
        ];
    }

    private function applyLocationFilter($query, ?string $city, ?string $state): void
    {
        if ($city === null && $state === null) {
            return;
        }

        if ($city !== null && Schema::hasColumn('rounds', 'city')) {
            $query->where('city', $city);
        }

        if ($state !== null && Schema::hasColumn('rounds', 'state')) {
            $query->where('state', $state);
        }
    }

    private function normalizeCity(?string $city): ?string
    {
        if ($city === null) {
            return null;
        }

        $clean = trim($city);

        return $clean === '' ? null : $clean;
    }

    private function normalizeState(?string $state): ?string
    {
        if ($state === null) {
            return null;
        }

        $clean = strtoupper(trim($state));

        return $clean === '' ? null : $clean;
    }
}
