<?php
/**
 * AURA FARMING — Etapa 8
 * Histórico, estatísticas, rankings por período/localização e seguidores.
 */

function afPeriodoValido(string $periodo): string
{
    return in_array($periodo, ['diario','semanal','mensal','global'], true) ? $periodo : 'global';
}

function afEscopoValido(string $escopo): string
{
    return in_array($escopo, ['global','nacional','regional','cidade','amigos'], true) ? $escopo : 'global';
}

function afPeriodoSql(string $periodo, string $alias = 'p'): string
{
    $periodo = afPeriodoValido($periodo);
    return match ($periodo) {
        'diario'  => " AND {$alias}.finalizada_em >= CURDATE() ",
        'semanal' => " AND {$alias}.finalizada_em >= DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY) ",
        'mensal'  => " AND {$alias}.finalizada_em >= DATE_FORMAT(CURDATE(), '%Y-%m-01') ",
        default   => '',
    };
}

function afContextoLocalizacao(array $usuario): array
{
    return [
        'cidade' => trim((string)($usuario['cidade'] ?? '')),
        'estado' => trim((string)($usuario['estado'] ?? '')),
        'pais' => trim((string)($usuario['pais'] ?? '')) ?: 'Brasil',
    ];
}

function afEscopoSql(string $escopo, array $usuario, array &$params): array
{
    $escopo = afEscopoValido($escopo);
    $local = afContextoLocalizacao($usuario);
    $disponivel = true;
    $rotulo = 'Mundo';
    $sql = '';

    switch ($escopo) {
        case 'nacional':
            $sql = " AND COALESCE(NULLIF(TRIM(pr.pais),''),'Brasil') = ? ";
            $params[] = $local['pais'];
            $rotulo = $local['pais'];
            break;
        case 'regional':
            if ($local['estado'] === '') {
                $disponivel = false;
            } else {
                $sql = " AND TRIM(COALESCE(pr.estado,'')) = ? AND COALESCE(NULLIF(TRIM(pr.pais),''),'Brasil') = ? ";
                $params[] = $local['estado'];
                $params[] = $local['pais'];
                $rotulo = $local['estado'];
            }
            break;
        case 'cidade':
            if ($local['cidade'] === '' || $local['estado'] === '') {
                $disponivel = false;
            } else {
                $sql = " AND TRIM(COALESCE(pr.cidade,'')) = ? AND TRIM(COALESCE(pr.estado,'')) = ? AND COALESCE(NULLIF(TRIM(pr.pais),''),'Brasil') = ? ";
                $params[] = $local['cidade'];
                $params[] = $local['estado'];
                $params[] = $local['pais'];
                $rotulo = $local['cidade'] . ' • ' . $local['estado'];
            }
            break;
        case 'amigos':
            $sql = " AND (u.id = ? OR EXISTS (SELECT 1 FROM af_seguidores sf WHERE sf.seguidor_id=? AND sf.seguido_id=u.id)) ";
            $params[] = (int)$usuario['id'];
            $params[] = (int)$usuario['id'];
            $rotulo = 'Jogadores que você segue';
            break;
        default:
            $rotulo = 'Mundo';
    }

    return ['sql'=>$sql,'disponivel'=>$disponivel,'rotulo'=>$rotulo,'local'=>$local];
}

function afRanking(PDO $pdo, string $periodo, string $escopo, array $usuario, int $limite = 50, int $offset = 0): array
{
    $periodo = afPeriodoValido($periodo);
    $escopo = afEscopoValido($escopo);
    $limite = max(1, min(100, $limite));
    $offset = max(0, $offset);

    $params = [];
    $scope = afEscopoSql($escopo, $usuario, $params);
    if (!$scope['disponivel']) {
        return ['itens'=>[], 'periodo'=>$periodo, 'escopo'=>$escopo, 'rotulo'=>$scope['rotulo'], 'disponivel'=>false, 'minha_posicao'=>0, 'minha_pontuacao'=>0, 'total'=>0];
    }

    $periodSql = afPeriodoSql($periodo, 'p');
    $eligibility = function_exists('afMinorPolicyRankingEligibilitySql')
        ? afMinorPolicyRankingEligibilitySql('ag','u')
        : "ag.status_idade IN ('adult_verified','guardian_verified')";
    $baseWhere = "u.status=1 AND p.status='finalizada' AND p.antifraude_status='aprovada' AND COALESCE(p.admin_status,'normal')='normal' AND p.controlled_event_id IS NULL AND {$eligibility} {$periodSql} {$scope['sql']}";
    $joins = "JOIN af_partidas p ON p.usuario_id=u.id LEFT JOIN af_perfis pr ON pr.usuario_id=u.id JOIN af_user_age_profiles ag ON ag.usuario_id=u.id";
    $sql = "SELECT u.id,u.nome,u.username,u.aura_id,u.foto_perfil,u.foto_externa,u.titulo,
                   pr.cidade,pr.estado,COALESCE(NULLIF(TRIM(pr.pais),''),'Brasil') pais,
                   ag.tipo_conta,ag.status_idade,ag.idade_declarada,
                   MAX(p.pontuacao_validada) melhor_pontuacao,
                   AVG(p.pontuacao_validada) media_pontuacao,
                   COUNT(p.id) partidas_periodo,
                   MAX(p.finalizada_em) ultimo_resultado,
                   MAX(p.combo_maximo) combo_maximo,
                   SUM(p.likes_recebidos) likes_periodo,
                   SUM(p.superlikes_recebidos) superlikes_periodo
            FROM af_usuarios u {$joins}
            WHERE {$baseWhere}
            GROUP BY u.id,u.nome,u.username,u.aura_id,u.foto_perfil,u.foto_externa,u.titulo,pr.cidade,pr.estado,pr.pais,ag.tipo_conta,ag.status_idade,ag.idade_declarada
            ORDER BY melhor_pontuacao DESC,media_pontuacao DESC,ultimo_resultado ASC
            LIMIT {$limite} OFFSET {$offset}";
    $st = $pdo->prepare($sql);$st->execute($params);$itens = $st->fetchAll();

    $countSql = "SELECT COUNT(*) FROM (SELECT u.id FROM af_usuarios u {$joins} WHERE {$baseWhere} GROUP BY u.id) rank_total";
    $stCount=$pdo->prepare($countSql);$stCount->execute($params);$total=(int)$stCount->fetchColumn();

    $myParams=$params;$myParams[]=(int)$usuario['id'];
    $mySql="SELECT MAX(p.pontuacao_validada) FROM af_usuarios u {$joins} WHERE {$baseWhere} AND u.id=?";
    $stMy=$pdo->prepare($mySql);$stMy->execute($myParams);$myScore=(float)($stMy->fetchColumn()?:0);

    $myPosition=0;
    if($myScore>0){
        $posParams=$params;$posParams[]=$myScore;
        $posSql="SELECT COUNT(*)+1 FROM (SELECT u.id,MAX(p.pontuacao_validada) score FROM af_usuarios u {$joins} WHERE {$baseWhere} GROUP BY u.id) melhores WHERE score>?";
        $stPos=$pdo->prepare($posSql);$stPos->execute($posParams);$myPosition=(int)($stPos->fetchColumn()?:1);
    }

    foreach($itens as $i=>&$item){
        $item['posicao']=$offset+$i+1;$item['seguindo']=false;
        if(function_exists('afMinorPolicyProtectRankingItem'))$item=afMinorPolicyProtectRankingItem($item);
    }unset($item);

    if($itens){
        $ids=array_map(fn($x)=>(int)$x['id'],$itens);$placeholders=implode(',',array_fill(0,count($ids),'?'));
        $followParams=array_merge([(int)$usuario['id']],$ids);
        $stFollow=$pdo->prepare("SELECT seguido_id FROM af_seguidores WHERE seguidor_id=? AND seguido_id IN ({$placeholders})");$stFollow->execute($followParams);
        $following=array_flip(array_map('intval',$stFollow->fetchAll(PDO::FETCH_COLUMN)));
        foreach($itens as &$item)$item['seguindo']=empty($item['minor_protected'])&&isset($following[(int)$item['id']]);unset($item);
    }

    return ['itens'=>$itens,'periodo'=>$periodo,'escopo'=>$escopo,'rotulo'=>$scope['rotulo'],'disponivel'=>true,'minha_posicao'=>$myPosition,'minha_pontuacao'=>$myScore,'total'=>$total];
}

function afCalcularPosicaoPeriodo(PDO $pdo, int $usuarioId, string $periodo = 'global'): int
{
    $periodo=afPeriodoValido($periodo);$periodSql=afPeriodoSql($periodo,'p');
    $eligibility=function_exists('afMinorPolicyRankingEligibilitySql')?afMinorPolicyRankingEligibilitySql('ag','u'):"ag.status_idade IN ('adult_verified','guardian_verified')";
    $st=$pdo->prepare("SELECT MAX(p.pontuacao_validada) FROM af_partidas p JOIN af_usuarios u ON u.id=p.usuario_id JOIN af_user_age_profiles ag ON ag.usuario_id=u.id WHERE p.usuario_id=? AND {$eligibility} AND p.status='finalizada' AND p.antifraude_status='aprovada' AND COALESCE(p.admin_status,'normal')='normal' AND p.controlled_event_id IS NULL {$periodSql}");
    $st->execute([$usuarioId]);$score=(float)($st->fetchColumn()?:0);if($score<=0)return 0;
    $st=$pdo->prepare("SELECT COUNT(*)+1 FROM (SELECT p.usuario_id,MAX(p.pontuacao_validada) score FROM af_partidas p JOIN af_usuarios u ON u.id=p.usuario_id JOIN af_user_age_profiles ag ON ag.usuario_id=u.id WHERE {$eligibility} AND p.status='finalizada' AND p.antifraude_status='aprovada' AND COALESCE(p.admin_status,'normal')='normal' AND p.controlled_event_id IS NULL {$periodSql} GROUP BY p.usuario_id) melhores WHERE score>?");
    $st->execute([$score]);return (int)($st->fetchColumn()?:1);
}

function afEstatisticasUsuario(PDO $pdo, int $usuarioId): array
{
    $st = $pdo->prepare("SELECT
        COUNT(*) total_partidas,
        COALESCE(MAX(pontuacao_validada),0) melhor_pontuacao,
        COALESCE(AVG(pontuacao_validada),0) media_pontuacao,
        COALESCE(SUM(aura_gerada),0) aura_gerada,
        COALESCE(SUM(likes_recebidos),0) likes,
        COALESCE(SUM(superlikes_recebidos),0) superlikes,
        COALESCE(MAX(combo_maximo),1) combo_maximo,
        COALESCE(MAX(combo_hits_maximo),0) combo_hits_maximo,
        COALESCE(SUM(combo_sequencias_concluidas),0) combo_sequencias,
        COALESCE(MAX(combo_perfect_chain_max),0) perfect_chain_max,
        COALESCE(AVG(combo_ritmo_medio),0) combo_ritmo_medio,
        COALESCE(AVG(precisao_media),0) precisao_media,
        COALESCE(AVG(fluidez_media),0) fluidez_media,
        COALESCE(AVG(originalidade_media),0) originalidade_media,
        COALESCE(SUM(movimentos_reconhecidos),0) movimentos,
        COALESCE(SUM(perfect_moves),0) perfect_moves,
        COALESCE(SUM(xp_ganho),0) xp_ganho,
        COALESCE(SUM(duracao_real_segundos),0) segundos_jogados,
        COALESCE(SUM(novo_recorde),0) recordes,
        MAX(finalizada_em) ultima_partida
      FROM af_partidas WHERE usuario_id=? AND status='finalizada' AND antifraude_status='aprovada' AND COALESCE(admin_status,'normal')='normal' AND controlled_event_id IS NULL");
    $st->execute([$usuarioId]);
    $stats = $st->fetch() ?: [];

    $st7 = $pdo->prepare("SELECT COUNT(*) partidas_7d,COALESCE(MAX(pontuacao_validada),0) melhor_7d,COALESCE(AVG(pontuacao_validada),0) media_7d
                          FROM af_partidas WHERE usuario_id=? AND status='finalizada' AND antifraude_status='aprovada' AND COALESCE(admin_status,'normal')='normal' AND controlled_event_id IS NULL AND finalizada_em>=DATE_SUB(NOW(),INTERVAL 7 DAY)");
    $st7->execute([$usuarioId]);
    return array_merge($stats, $st7->fetch() ?: []);
}

function afHistoricoUsuario(PDO $pdo, int $usuarioId, int $pagina = 1, int $porPagina = 10): array
{
    $pagina = max(1, $pagina);
    $porPagina = max(1, min(50, $porPagina));
    $offset = ($pagina - 1) * $porPagina;
    $st = $pdo->prepare("SELECT * FROM af_partidas
                         WHERE usuario_id=? AND status='finalizada' AND controlled_event_id IS NULL
                         ORDER BY finalizada_em DESC,id DESC
                         LIMIT {$porPagina} OFFSET {$offset}");
    $st->execute([$usuarioId]);
    $itens = $st->fetchAll();
    $st = $pdo->prepare("SELECT COUNT(*) FROM af_partidas WHERE usuario_id=? AND status='finalizada' AND controlled_event_id IS NULL");
    $st->execute([$usuarioId]);
    $total = (int)$st->fetchColumn();
    return [
        'itens'=>$itens,'pagina'=>$pagina,'por_pagina'=>$porPagina,'total'=>$total,
        'total_paginas'=>max(1,(int)ceil($total/$porPagina)),
    ];
}

function afNovoShareToken(PDO $pdo, int $ignorarPartidaId = 0): string
{
    do {
        $token = bin2hex(random_bytes(8));
        $st = $pdo->prepare('SELECT id FROM af_partidas WHERE share_token=? AND id<>? LIMIT 1');
        $st->execute([$token,$ignorarPartidaId]);
    } while ($st->fetchColumn());
    return $token;
}

function afGerarShareToken(PDO $pdo, int $partidaId, string $sessaoId = ''): string
{
    $token = afNovoShareToken($pdo,$partidaId);
    $pdo->prepare('UPDATE af_partidas SET share_token=? WHERE id=?')->execute([$token,$partidaId]);
    return $token;
}

function afBuscarResultadoPublico(PDO $pdo, string $token): ?array
{
    $token = preg_replace('/[^a-f0-9]/','',strtolower($token));
    if (strlen($token)!==16) return null;
    $st = $pdo->prepare("SELECT p.*,u.nome,u.username,u.aura_id,u.foto_perfil,u.foto_externa,u.titulo,u.nivel,
                                pr.cidade,pr.estado,COALESCE(NULLIF(TRIM(pr.pais),''),'Brasil') pais
                         FROM af_partidas p
                         JOIN af_usuarios u ON u.id=p.usuario_id
                         LEFT JOIN af_perfis pr ON pr.usuario_id=u.id
                         WHERE p.share_token=? AND p.status='finalizada' AND p.antifraude_status='aprovada' AND COALESCE(p.admin_status,'normal')='normal' AND p.controlled_event_id IS NULL AND u.status=1 LIMIT 1");
    $st->execute([$token]);
    return $st->fetch() ?: null;
}

function afSeguindo(PDO $pdo, int $seguidorId, int $seguidoId): bool
{
    $st = $pdo->prepare('SELECT 1 FROM af_seguidores WHERE seguidor_id=? AND seguido_id=? LIMIT 1');
    $st->execute([$seguidorId,$seguidoId]);
    return (bool)$st->fetchColumn();
}

function afDefinirSeguindo(PDO $pdo, int $seguidorId, int $seguidoId, bool $seguir): bool
{
    if ($seguidorId === $seguidoId) throw new RuntimeException('Você não pode seguir a própria conta.');
    $st = $pdo->prepare('SELECT id FROM af_usuarios WHERE id=? AND status=1 LIMIT 1');
    $st->execute([$seguidoId]);
    if (!$st->fetchColumn()) throw new RuntimeException('Jogador não encontrado.');
    if ($seguir) {
        $stInsert = $pdo->prepare('INSERT IGNORE INTO af_seguidores(seguidor_id,seguido_id,criado_em) VALUES (?,?,NOW())');
        $stInsert->execute([$seguidorId,$seguidoId]);
        if ($stInsert->rowCount() > 0 && function_exists('criarNotificacao')) {
            $stNome = $pdo->prepare('SELECT nome,aura_id FROM af_usuarios WHERE id=? LIMIT 1');
            $stNome->execute([$seguidorId]);
            $seguidor = $stNome->fetch() ?: ['nome'=>'Um jogador','aura_id'=>''];
            criarNotificacao($pdo,$seguidoId,'novo_seguidor','Novo seguidor',($seguidor['nome'].' ('.$seguidor['aura_id'].') começou a seguir você.'));
        }
    } else {
        $pdo->prepare('DELETE FROM af_seguidores WHERE seguidor_id=? AND seguido_id=?')->execute([$seguidorId,$seguidoId]);
    }
    return afSeguindo($pdo,$seguidorId,$seguidoId);
}

function afContadoresSociais(PDO $pdo, int $usuarioId): array
{
    $st = $pdo->prepare('SELECT (SELECT COUNT(*) FROM af_seguidores WHERE seguido_id=?) seguidores,(SELECT COUNT(*) FROM af_seguidores WHERE seguidor_id=?) seguindo');
    $st->execute([$usuarioId,$usuarioId]);
    $r = $st->fetch() ?: ['seguidores'=>0,'seguindo'=>0];
    return ['seguidores'=>(int)$r['seguidores'],'seguindo'=>(int)$r['seguindo']];
}

function afRegistrarCompartilhamento(PDO $pdo, int $partidaId, int $usuarioId, string $canal): void
{
    $permitidos = ['webshare','whatsapp','instagram','tiktok','facebook','x','copiar','outro'];
    if (!in_array($canal,$permitidos,true)) $canal='outro';
    $pdo->prepare('INSERT INTO af_compartilhamentos(partida_id,usuario_id,canal,criado_em) VALUES (?,?,?,NOW())')
        ->execute([$partidaId,$usuarioId,$canal]);
}
