<?php
declare(strict_types=1);

namespace App\Modules\Reports\Services;

use App\Core\App;

final class PlayerRetentionReportService
{
    /**
     * Generate player retention report: enrollment counts, churn rate, active vs dropped.
     *
     * @param string $periodFrom Start date (YYYY-MM-DD)
     * @param string $periodTo   End date (YYYY-MM-DD)
     * @return array Report data
     */
    public static function generate(string $periodFrom, string $periodTo): array
    {
        $db = App::getInstance()->db();

        // Total active players at start of period
        $activeAtStart = $db->selectOne(
            "SELECT COUNT(DISTINCT tgp.player_id) AS cnt
             FROM training_group_players tgp
             WHERE tgp.joined_at < ?
               AND (tgp.left_at IS NULL OR tgp.left_at >= ?)",
            [$periodFrom, $periodFrom]
        );
        $startCount = (int) ($activeAtStart['cnt'] ?? 0);

        // New enrollments during period
        $newEnrollments = $db->selectOne(
            "SELECT COUNT(DISTINCT tgp.player_id) AS cnt
             FROM training_group_players tgp
             WHERE tgp.joined_at BETWEEN ? AND ?",
            [$periodFrom, $periodTo]
        );
        $newCount = (int) ($newEnrollments['cnt'] ?? 0);

        // Dropped during period (left_at within range)
        $dropped = $db->selectOne(
            "SELECT COUNT(DISTINCT tgp.player_id) AS cnt
             FROM training_group_players tgp
             WHERE tgp.left_at BETWEEN ? AND ?",
            [$periodFrom, $periodTo]
        );
        $droppedCount = (int) ($dropped['cnt'] ?? 0);

        // Active at end of period
        $activeAtEnd = $db->selectOne(
            "SELECT COUNT(DISTINCT tgp.player_id) AS cnt
             FROM training_group_players tgp
             WHERE tgp.joined_at <= ?
               AND (tgp.left_at IS NULL OR tgp.left_at > ?)",
            [$periodTo, $periodTo]
        );
        $endCount = (int) ($activeAtEnd['cnt'] ?? 0);

        // Churn rate
        $churnRate = $startCount > 0 ? round(($droppedCount / $startCount) * 100, 2) : 0;

        // Retention rate
        $retentionRate = $startCount > 0 ? round((($startCount - $droppedCount) / $startCount) * 100, 2) : 0;

        // Net growth
        $netGrowth = $newCount - $droppedCount;

        // Monthly breakdown
        $monthlyBreakdown = $db->select(
            "SELECT
                DATE_FORMAT(dates.month_date, '%Y-%m') AS month,
                COALESCE(new_t.cnt, 0) AS new_enrollments,
                COALESCE(drop_t.cnt, 0) AS dropped
             FROM (
                 SELECT DISTINCT DATE_FORMAT(joined_at, '%Y-%m-01') AS month_date
                 FROM training_group_players
                 WHERE joined_at BETWEEN ? AND ?
                 UNION
                 SELECT DISTINCT DATE_FORMAT(left_at, '%Y-%m-01') AS month_date
                 FROM training_group_players
                 WHERE left_at BETWEEN ? AND ?
             ) dates
             LEFT JOIN (
                 SELECT DATE_FORMAT(joined_at, '%Y-%m-01') AS m, COUNT(DISTINCT player_id) AS cnt
                 FROM training_group_players
                 WHERE joined_at BETWEEN ? AND ?
                 GROUP BY m
             ) new_t ON new_t.m = dates.month_date
             LEFT JOIN (
                 SELECT DATE_FORMAT(left_at, '%Y-%m-01') AS m, COUNT(DISTINCT player_id) AS cnt
                 FROM training_group_players
                 WHERE left_at BETWEEN ? AND ?
                 GROUP BY m
             ) drop_t ON drop_t.m = dates.month_date
             ORDER BY dates.month_date ASC",
            [$periodFrom, $periodTo, $periodFrom, $periodTo, $periodFrom, $periodTo, $periodFrom, $periodTo]
        );

        // By academy breakdown
        $byAcademy = $db->select(
            "SELECT a.id, a.name_ar,
                    COUNT(DISTINCT CASE WHEN tgp.joined_at BETWEEN ? AND ? THEN tgp.player_id END) AS new_enrollments,
                    COUNT(DISTINCT CASE WHEN tgp.left_at BETWEEN ? AND ? THEN tgp.player_id END) AS dropped,
                    COUNT(DISTINCT CASE WHEN (tgp.left_at IS NULL OR tgp.left_at > ?) AND tgp.joined_at <= ? THEN tgp.player_id END) AS active_now
             FROM training_groups tg
             LEFT JOIN academies a ON a.id = tg.academy_id
             LEFT JOIN training_group_players tgp ON tgp.group_id = tg.id
             WHERE a.id IS NOT NULL
             GROUP BY a.id, a.name_ar
             HAVING new_enrollments > 0 OR dropped > 0 OR active_now > 0
             ORDER BY a.name_ar ASC",
            [$periodFrom, $periodTo, $periodFrom, $periodTo, $periodTo, $periodTo]
        );

        return [
            'period_from'       => $periodFrom,
            'period_to'         => $periodTo,
            'summary' => [
                'active_at_start'   => $startCount,
                'new_enrollments'   => $newCount,
                'dropped'           => $droppedCount,
                'active_at_end'     => $endCount,
                'churn_rate'        => $churnRate,
                'retention_rate'    => $retentionRate,
                'net_growth'        => $netGrowth,
            ],
            'monthly_breakdown' => $monthlyBreakdown,
            'by_academy'        => $byAcademy,
        ];
    }
}
