<?php

declare(strict_types=1);

namespace Pesisportaali\Services;

final class StandingsService
{
    public function build(
        array $groupMatches,
        array $relatedMatches = []
    ): array {
        $teams = [];

        /*
         * Taulukon joukkueet muodostetaan vain varsinaisen lohkon
         * otteluista. Ristikkäislohkon vastustajia ei lisätä taulukkoon.
         */
        foreach ($groupMatches as $match) {
            foreach (['home', 'away'] as $side) {
                $team = $match[$side] ?? null;

                if (!is_array($team) || empty($team['id'])) {
                    continue;
                }

                $teamId = (int)$team['id'];

                if (!isset($teams[$teamId])) {
                    $teams[$teamId] = $this->teamTemplate($team);
                }
            }
        }

        /*
         * Yhdistetään lohkon ja siihen liittyvien ryhmien ottelut.
         * Ottelut yksilöidään ID:n perusteella, jotta samaa ottelua
         * ei lasketa kahteen kertaan.
         */
        $matches = [];

        foreach ([$groupMatches, $relatedMatches] as $matchSet) {
            foreach ($matchSet as $match) {
                if (!is_array($match)) {
                    continue;
                }

                $matchId = (int)($match['id'] ?? 0);

                if ($matchId > 0) {
                    $matches[$matchId] = $match;
                }
            }
        }

        foreach ($matches as $match) {
            $result = $match['result'] ?? null;

            if (!is_array($result)) {
                continue;
            }

            $homeId = (int)($match['home']['id'] ?? 0);
            $awayId = (int)($match['away']['id'] ?? 0);

            if ($homeId <= 0 || $awayId <= 0) {
                continue;
            }

            $homePeriods = $this->periods($result, 'home');
            $awayPeriods = $this->periods($result, 'away');

            $homeRuns = $this->runs($result, 'home');
            $awayRuns = $this->runs($result, 'away');

            $rows = [
                [
                    'team_id' => $homeId,
                    'own_periods' => $homePeriods,
                    'opponent_periods' => $awayPeriods,
                    'own_runs' => $homeRuns,
                    'opponent_runs' => $awayRuns,
                ],
                [
                    'team_id' => $awayId,
                    'own_periods' => $awayPeriods,
                    'opponent_periods' => $homePeriods,
                    'own_runs' => $awayRuns,
                    'opponent_runs' => $homeRuns,
                ],
            ];

            foreach ($rows as $row) {
                $teamId = $row['team_id'];

                /*
                 * Vastustaja voi olla ristikkäislohkosta.
                 * Silloin sen tulosta ei lisätä tämän lohkon taulukkoon.
                 */
                if (!isset($teams[$teamId])) {
                    continue;
                }

                $teams[$teamId]['matches']++;
                $teams[$teamId]['periods_for'] += $row['own_periods'];
                $teams[$teamId]['periods_against'] += $row['opponent_periods'];
                $teams[$teamId]['runs_for'] += $row['own_runs'];
                $teams[$teamId]['runs_against'] += $row['opponent_runs'];

                if ($row['own_periods'] > $row['opponent_periods']) {
                    $teams[$teamId]['wins']++;
                    $teams[$teamId]['points'] += 3;
                } elseif ($row['own_periods'] < $row['opponent_periods']) {
                    $teams[$teamId]['losses']++;
                } else {
                    $teams[$teamId]['draws']++;
                    $teams[$teamId]['points'] += 1;
                }
            }
        }

        $standings = array_values($teams);

        foreach ($standings as &$team) {
            $team['period_diff'] =
                $team['periods_for'] - $team['periods_against'];

            $team['run_diff'] =
                $team['runs_for'] - $team['runs_against'];
        }
        unset($team);

        usort($standings, function (array $a, array $b): int {
            return
                ($b['points'] <=> $a['points'])
                ?: ($b['period_diff'] <=> $a['period_diff'])
                ?: ($b['run_diff'] <=> $a['run_diff'])
                ?: ($b['periods_for'] <=> $a['periods_for'])
                ?: ($b['runs_for'] <=> $a['runs_for'])
                ?: strcasecmp($a['name'], $b['name']);
        });

        foreach ($standings as $index => &$team) {
            $team['rank'] = $index + 1;
        }
        unset($team);

        return $standings;
    }

    private function teamTemplate(array $team): array
    {
        return [
            'id' => (int)($team['id'] ?? 0),
            'name' => trim((string)(
                $team['name']
                ?? $team['shorthand']
                ?? ''
            )),
            'short' => trim((string)(
                $team['shorthand']
                ?? $team['name']
                ?? ''
            )),
            'logo' => (string)(
                $team['logo']
                ?? $team['icon']
                ?? $team['square']
                ?? ''
            ),
            'matches' => 0,
            'wins' => 0,
            'draws' => 0,
            'losses' => 0,
            'points' => 0,
            'periods_for' => 0,
            'periods_against' => 0,
            'period_diff' => 0,
            'runs_for' => 0,
            'runs_against' => 0,
            'run_diff' => 0,
            'rank' => null,
        ];
    }

    private function periods(array $result, string $side): int
    {
        $details = is_array($result['details'] ?? null)
            ? $result['details']
            : [];

        return (int)(
            $result['periods_' . $side]
            ?? $details['periods_' . $side]
            ?? 0
        );
    }

    private function runs(array $result, string $side): int
    {
        $details = is_array($result['details'] ?? null)
            ? $result['details']
            : [];

        $prefix = $side === 'home'
            ? 'runs_home_'
            : 'runs_away_';

        $fields = [
            'first_period',
            'second_period',
            'super_inning',
            'scoring_contest',
        ];

        $total = 0;

        foreach ($fields as $field) {
            $key = $prefix . $field;

            $total += (int)(
                $result[$key]
                ?? $details[$key]
                ?? 0
            );
        }

        return $total;
    }
}
