<?php

class UserActivityService
{
    private PDO $pdo;
    private string $schema;
    private array $tableCache = [];
    private array $columnsCache = [];

    public function __construct(PDO $pdo)
    {
        $this->pdo = $pdo;
        $this->schema = (string)$this->pdo->query('SELECT DATABASE()')->fetchColumn();
    }

    public function getMyMatches(int $userId): array
    {
        if (!$this->hasTable('matches')) {
            return [];
        }

        $matchesColumns = $this->getColumns('matches');

        $idCol = $this->pickColumn($matchesColumns, ['ID', 'id', 'match_id']);
        $team1Col = $this->pickColumn($matchesColumns, ['Team1_ID', 'team1_id']);
        $team2Col = $this->pickColumn($matchesColumns, ['Team2_ID', 'team2_id']);
        $startCol = $this->pickColumn($matchesColumns, ['StartTime', 'start_time', 'date', 'match_date']);
        $statusCol = $this->pickColumn($matchesColumns, ['Status', 'status']);
        $scoreCol = $this->pickColumn($matchesColumns, ['Score', 'score', 'result']);
        $participantsCol = $this->pickColumn($matchesColumns, ['Participants', 'participants', 'user_ids', 'player_ids']);
        $leagueNameCol = $this->pickColumn($matchesColumns, ['LeagueName', 'league_name', 'league', 'League']);
        $matchTypeCol = $this->pickColumn($matchesColumns, ['MatchType', 'match_type']);

        if (!$idCol) {
            return [];
        }

        $select = ["m.`{$idCol}` AS match_id"];
        if ($team1Col) {
            $select[] = "m.`{$team1Col}` AS team1_id";
        }
        if ($team2Col) {
            $select[] = "m.`{$team2Col}` AS team2_id";
        }
        if ($startCol) {
            $select[] = "m.`{$startCol}` AS match_date";
        }
        if ($statusCol) {
            $select[] = "m.`{$statusCol}` AS match_status";
        }
        if ($scoreCol) {
            $select[] = "m.`{$scoreCol}` AS match_score";
        }
        if ($leagueNameCol) {
            $select[] = "m.`{$leagueNameCol}` AS league_name";
        }
        if ($matchTypeCol) {
            $select[] = "m.`{$matchTypeCol}` AS match_type";
        }
        if ($participantsCol) {
            $select[] = "m.`{$participantsCol}` AS participants_raw";
        }

        $teamIds = $this->resolveUserTeamIds($userId);
        $where = [];
        $params = [':user_id' => $userId];

        if ($team1Col && $team2Col) {
            $teamChecks = ['(m.`' . $team1Col . '` = :user_id OR m.`' . $team2Col . '` = :user_id)'];
            foreach ($teamIds as $index => $teamId) {
                $key = ':team_' . $index;
                $params[$key] = $teamId;
                $teamChecks[] = '(m.`' . $team1Col . '` = ' . $key . ' OR m.`' . $team2Col . '` = ' . $key . ')';
            }
            $where[] = '(' . implode(' OR ', $teamChecks) . ')';
        }

        if ($participantsCol) {
            $where[] = "CONCAT(',', REPLACE(REPLACE(REPLACE(COALESCE(m.`{$participantsCol}`, ''), '[', ''), ']', ''), ' ', ''), ',') LIKE :participant_like";
            $params[':participant_like'] = '%,' . $userId . ',%';
        }

        if (empty($where)) {
            return [];
        }

        $orderBy = $startCol ? "m.`{$startCol}` DESC" : "m.`{$idCol}` DESC";
        $sql = 'SELECT ' . implode(', ', $select) . ' FROM `matches` m WHERE ' . implode(' OR ', $where) . ' ORDER BY ' . $orderBy . ' LIMIT 500';
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute($params);
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $result = [];
        foreach ($rows as $row) {
            $opponent = '';
            if (isset($row['team1_id'], $row['team2_id'])) {
                $team1Id = (int)$row['team1_id'];
                $team2Id = (int)$row['team2_id'];
                $opponentTeamId = $team1Id === $userId ? $team2Id : $team1Id;
                if (in_array($team1Id, $teamIds, true)) {
                    $opponentTeamId = $team2Id;
                }
                if (in_array($team2Id, $teamIds, true)) {
                    $opponentTeamId = $team1Id;
                }
                $opponent = $opponentTeamId > 0 ? 'Drużyna #' . $opponentTeamId : '';
            }

            $result[] = [
                'match_id' => (int)$row['match_id'],
                'opponent' => $opponent,
                'date' => !empty($row['match_date']) ? gmdate('Y-m-d\\TH:i:s\\Z', strtotime((string)$row['match_date'])) : null,
                'status' => $this->normalizeStatus($row['match_status'] ?? ''),
                'score' => $row['match_score'] ?? '',
                'league' => $row['league_name'] ?? ($row['match_type'] ?? '')
            ];
        }

        return $result;
    }

    public function getMyTournaments(int $userId): array
    {
        if (!$this->hasTable('tournaments')) {
            return [];
        }

        $tColumns = $this->getColumns('tournaments');

        $idCol = $this->pickColumn($tColumns, ['id', 'ID', 'tournament_id']);
        $nameCol = $this->pickColumn($tColumns, ['name', 'title', 'tournament_name']);
        $startDateCol = $this->pickColumn($tColumns, ['start_date', 'startDate', 'start_time', 'created_at']);
        $statusCol = $this->pickColumn($tColumns, ['status', 'state']);
        $playedCol = $this->pickColumn($tColumns, ['matches_played', 'played_matches']);
        $totalCol = $this->pickColumn($tColumns, ['total_matches', 'matches_total', 'matches_count']);

        if (!$idCol) {
            return [];
        }

        $membership = $this->resolveMembership('tournament');
        $rows = [];

        if ($membership !== null) {
            $sql = "SELECT
                        t.`{$idCol}` AS tournament_id,
                        " . ($nameCol ? "t.`{$nameCol}`" : "''") . " AS tournament_name,
                        " . ($startDateCol ? "t.`{$startDateCol}`" : "NULL") . " AS start_date,
                        " . ($statusCol ? "t.`{$statusCol}`" : "''") . " AS tournament_status,
                        " . ($playedCol ? "COALESCE(t.`{$playedCol}`, 0)" : '0') . " AS matches_played,
                        " . ($totalCol ? "COALESCE(t.`{$totalCol}`, 0)" : '0') . " AS total_matches
                    FROM `{$membership['table']}` rel
                    INNER JOIN `tournaments` t ON t.`{$idCol}` = rel.`{$membership['entityColumn']}`
                    WHERE rel.`{$membership['userColumn']}` = :user_id
                    ORDER BY tournament_id DESC
                    LIMIT 500";

            $stmt = $this->pdo->prepare($sql);
            $stmt->execute([':user_id' => $userId]);
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
        } else {
            $participantsCol = $this->pickColumn($tColumns, ['participants', 'user_ids', 'player_ids']);
            if (!$participantsCol) {
                return [];
            }

            $sql = "SELECT
                        t.`{$idCol}` AS tournament_id,
                        " . ($nameCol ? "t.`{$nameCol}`" : "''") . " AS tournament_name,
                        " . ($startDateCol ? "t.`{$startDateCol}`" : "NULL") . " AS start_date,
                        " . ($statusCol ? "t.`{$statusCol}`" : "''") . " AS tournament_status,
                        " . ($playedCol ? "COALESCE(t.`{$playedCol}`, 0)" : '0') . " AS matches_played,
                        " . ($totalCol ? "COALESCE(t.`{$totalCol}`, 0)" : '0') . " AS total_matches
                    FROM `tournaments` t
                    WHERE CONCAT(',', REPLACE(REPLACE(REPLACE(COALESCE(t.`{$participantsCol}`, ''), '[', ''), ']', ''), ' ', ''), ',') LIKE :participant_like
                    ORDER BY tournament_id DESC
                    LIMIT 500";

            $stmt = $this->pdo->prepare($sql);
            $stmt->execute([':participant_like' => '%,' . $userId . ',%']);
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
        }

        return array_map(function (array $row): array {
            return [
                'tournament_id' => (int)$row['tournament_id'],
                'name' => (string)($row['tournament_name'] ?? ''),
                'start_date' => !empty($row['start_date']) ? substr((string)$row['start_date'], 0, 10) : null,
                'status' => $this->normalizeStatus($row['tournament_status'] ?? ''),
                'matches_played' => (int)($row['matches_played'] ?? 0),
                'total_matches' => (int)($row['total_matches'] ?? 0)
            ];
        }, $rows);
    }

    public function getMyLeagues(int $userId): array
    {
        if (!$this->hasTable('leagues')) {
            return [];
        }

        $lColumns = $this->getColumns('leagues');

        $idCol = $this->pickColumn($lColumns, ['id', 'ID', 'league_id']);
        $nameCol = $this->pickColumn($lColumns, ['name', 'title', 'league_name']);
        $seasonCol = $this->pickColumn($lColumns, ['season', 'season_name']);
        $rankCol = $this->pickColumn($lColumns, ['rank', 'tier', 'division']);
        $statusCol = $this->pickColumn($lColumns, ['status', 'state']);
        $playedCol = $this->pickColumn($lColumns, ['matches_played', 'played_matches']);
        $pointsCol = $this->pickColumn($lColumns, ['points', 'score_points']);

        if (!$idCol) {
            return [];
        }

        $membership = $this->resolveMembership('league');
        $rows = [];

        if ($membership !== null) {
            $sql = "SELECT
                        l.`{$idCol}` AS league_id,
                        " . ($nameCol ? "l.`{$nameCol}`" : "''") . " AS league_name,
                        " . ($seasonCol ? "l.`{$seasonCol}`" : "''") . " AS season_name,
                        " . ($rankCol ? "l.`{$rankCol}`" : "''") . " AS league_rank,
                        " . ($statusCol ? "l.`{$statusCol}`" : "''") . " AS league_status,
                        " . ($playedCol ? "COALESCE(l.`{$playedCol}`, 0)" : '0') . " AS matches_played,
                        " . ($pointsCol ? "COALESCE(l.`{$pointsCol}`, 0)" : '0') . " AS points_total
                    FROM `{$membership['table']}` rel
                    INNER JOIN `leagues` l ON l.`{$idCol}` = rel.`{$membership['entityColumn']}`
                    WHERE rel.`{$membership['userColumn']}` = :user_id
                    ORDER BY league_id DESC
                    LIMIT 500";

            $stmt = $this->pdo->prepare($sql);
            $stmt->execute([':user_id' => $userId]);
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
        } else {
            $participantsCol = $this->pickColumn($lColumns, ['participants', 'user_ids', 'player_ids']);
            if (!$participantsCol) {
                return [];
            }

            $sql = "SELECT
                        l.`{$idCol}` AS league_id,
                        " . ($nameCol ? "l.`{$nameCol}`" : "''") . " AS league_name,
                        " . ($seasonCol ? "l.`{$seasonCol}`" : "''") . " AS season_name,
                        " . ($rankCol ? "l.`{$rankCol}`" : "''") . " AS league_rank,
                        " . ($statusCol ? "l.`{$statusCol}`" : "''") . " AS league_status,
                        " . ($playedCol ? "COALESCE(l.`{$playedCol}`, 0)" : '0') . " AS matches_played,
                        " . ($pointsCol ? "COALESCE(l.`{$pointsCol}`, 0)" : '0') . " AS points_total
                    FROM `leagues` l
                    WHERE CONCAT(',', REPLACE(REPLACE(REPLACE(COALESCE(l.`{$participantsCol}`, ''), '[', ''), ']', ''), ' ', ''), ',') LIKE :participant_like
                    ORDER BY league_id DESC
                    LIMIT 500";

            $stmt = $this->pdo->prepare($sql);
            $stmt->execute([':participant_like' => '%,' . $userId . ',%']);
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
        }

        return array_map(function (array $row): array {
            return [
                'league_id' => (int)$row['league_id'],
                'name' => (string)($row['league_name'] ?? ''),
                'season' => (string)($row['season_name'] ?? ''),
                'rank' => (string)($row['league_rank'] ?? ''),
                'status' => $this->normalizeStatus($row['league_status'] ?? ''),
                'matches_played' => (int)($row['matches_played'] ?? 0),
                'points' => (int)($row['points_total'] ?? 0)
            ];
        }, $rows);
    }

    private function resolveUserTeamIds(int $userId): array
    {
        $candidates = [
            ['table' => 'team_members', 'team' => 'team_id', 'user' => 'user_id'],
            ['table' => 'teams_users', 'team' => 'team_id', 'user' => 'user_id'],
            ['table' => 'user_teams', 'team' => 'team_id', 'user' => 'user_id'],
            ['table' => 'team_user', 'team' => 'team_id', 'user' => 'user_id']
        ];

        foreach ($candidates as $candidate) {
            if (!$this->hasTable($candidate['table'])) {
                continue;
            }

            $columns = $this->getColumns($candidate['table']);
            if (!in_array($candidate['team'], $columns, true) || !in_array($candidate['user'], $columns, true)) {
                continue;
            }

            $stmt = $this->pdo->prepare('SELECT `' . $candidate['team'] . '` FROM `' . $candidate['table'] . '` WHERE `' . $candidate['user'] . '` = :user_id');
            $stmt->execute([':user_id' => $userId]);
            $ids = $stmt->fetchAll(PDO::FETCH_COLUMN);

            $ids = array_values(array_unique(array_map('intval', $ids)));
            return array_values(array_filter($ids, fn($id) => $id > 0));
        }

        return [];
    }

    private function resolveMembership(string $entity): ?array
    {
        $map = [
            'tournament' => [
                ['table' => 'tournament_members', 'entity' => 'tournament_id', 'user' => 'user_id'],
                ['table' => 'tournaments_users', 'entity' => 'tournament_id', 'user' => 'user_id'],
                ['table' => 'user_tournaments', 'entity' => 'tournament_id', 'user' => 'user_id'],
                ['table' => 'tournament_participants', 'entity' => 'tournament_id', 'user' => 'user_id']
            ],
            'league' => [
                ['table' => 'league_members', 'entity' => 'league_id', 'user' => 'user_id'],
                ['table' => 'leagues_users', 'entity' => 'league_id', 'user' => 'user_id'],
                ['table' => 'user_leagues', 'entity' => 'league_id', 'user' => 'user_id'],
                ['table' => 'league_participants', 'entity' => 'league_id', 'user' => 'user_id']
            ]
        ];

        if (!isset($map[$entity])) {
            return null;
        }

        foreach ($map[$entity] as $candidate) {
            if (!$this->hasTable($candidate['table'])) {
                continue;
            }

            $columns = $this->getColumns($candidate['table']);
            if (!in_array($candidate['entity'], $columns, true) || !in_array($candidate['user'], $columns, true)) {
                continue;
            }

            return [
                'table' => $candidate['table'],
                'entityColumn' => $candidate['entity'],
                'userColumn' => $candidate['user']
            ];
        }

        return null;
    }

    private function hasTable(string $table): bool
    {
        if (array_key_exists($table, $this->tableCache)) {
            return $this->tableCache[$table];
        }

        $stmt = $this->pdo->prepare('SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = :schema AND table_name = :table');
        $stmt->execute([
            ':schema' => $this->schema,
            ':table' => $table
        ]);

        $exists = (int)$stmt->fetchColumn() > 0;
        $this->tableCache[$table] = $exists;

        return $exists;
    }

    private function getColumns(string $table): array
    {
        if (isset($this->columnsCache[$table])) {
            return $this->columnsCache[$table];
        }

        if (!$this->hasTable($table)) {
            $this->columnsCache[$table] = [];
            return [];
        }

        $stmt = $this->pdo->prepare('SELECT COLUMN_NAME FROM information_schema.columns WHERE table_schema = :schema AND table_name = :table');
        $stmt->execute([
            ':schema' => $this->schema,
            ':table' => $table
        ]);

        $columns = $stmt->fetchAll(PDO::FETCH_COLUMN);
        $this->columnsCache[$table] = is_array($columns) ? $columns : [];

        return $this->columnsCache[$table];
    }

    private function pickColumn(array $columns, array $candidates): ?string
    {
        foreach ($candidates as $candidate) {
            if (in_array($candidate, $columns, true)) {
                return $candidate;
            }
        }

        return null;
    }

    private function normalizeStatus(string $status): string
    {
        $status = mb_strtolower(trim($status));

        return match ($status) {
            'planned', 'planowany', 'zaplanowany' => 'zaplanowany',
            'live', 'ongoing', 'trwający', 'in_progress' => 'trwający',
            'end', 'ended', 'finished', 'zakończony' => 'zakończony',
            default => $status
        };
    }
}
