<?php
declare(strict_types=1);

namespace App\Modules\Coaches\Models;

use App\Core\Model;
use App\Core\App;

class CoachPerformanceMetric extends Model
{
    protected static string $table = 'coach_performance_metrics';
    protected static string $primaryKey = 'id';
    protected static bool $timestamps = false;
    protected static bool $softDelete = false;
    protected static bool $autoTrackAuthor = false;

    protected static array $fillable = [
        'coach_id',
        'period_month',
        'total_sessions_assigned',
        'total_sessions_conducted',
        'total_sessions_cancelled',
        'avg_attendance_rate',
        'avg_rating',
        'total_ratings_count',
        'total_players_trained',
        'player_retention_rate',
        'punctuality_rate',
        'revenue_generated',
        'calculated_at',
    ];

    /**
     * Get performance metrics for a coach over N months.
     */
    public static function getForCoach(int $coachId, int $months = 12): array
    {
        $db = App::getInstance()->db();
        return $db->select(
            "SELECT * FROM coach_performance_metrics
             WHERE coach_id = ?
             ORDER BY period_month DESC
             LIMIT ?",
            [$coachId, $months]
        );
    }

    /**
     * Get the latest performance metrics for a coach.
     */
    public static function getLatest(int $coachId): ?array
    {
        $db = App::getInstance()->db();
        return $db->selectOne(
            "SELECT * FROM coach_performance_metrics
             WHERE coach_id = ?
             ORDER BY period_month DESC
             LIMIT 1",
            [$coachId]
        );
    }

    /**
     * Calculate and store metrics for a coach for a specific month.
     */
    public static function calculateForMonth(int $coachId, string $month): array
    {
        $db = App::getInstance()->db();
        $monthStart = $month . '-01';
        $monthEnd = date('Y-m-t', strtotime($monthStart));

        // Sessions assigned and conducted
        $sessions = $db->selectOne(
            "SELECT
                COUNT(*) AS total_assigned,
                SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) AS total_conducted,
                SUM(CASE WHEN status = 'cancelled' THEN 1 ELSE 0 END) AS total_cancelled
             FROM training_sessions
             WHERE coach_id = ? AND session_date BETWEEN ? AND ?",
            [$coachId, $monthStart, $monthEnd]
        );

        $totalAssigned = (int) ($sessions['total_assigned'] ?? 0);
        $totalConducted = (int) ($sessions['total_conducted'] ?? 0);
        $totalCancelled = (int) ($sessions['total_cancelled'] ?? 0);

        // Average attendance rate for conducted sessions
        $attendance = $db->selectOne(
            "SELECT AVG(sub.rate) AS avg_rate FROM (
                SELECT ts.id,
                    CASE WHEN COUNT(sa.id) > 0
                        THEN SUM(CASE WHEN sa.status = 'present' THEN 1 ELSE 0 END) * 100.0 / COUNT(sa.id)
                        ELSE 0
                    END AS rate
                FROM training_sessions ts
                LEFT JOIN session_attendance sa ON sa.session_id = ts.id
                WHERE ts.coach_id = ? AND ts.session_date BETWEEN ? AND ? AND ts.status = 'completed'
                GROUP BY ts.id
            ) sub",
            [$coachId, $monthStart, $monthEnd]
        );
        $avgAttendanceRate = $attendance['avg_rate'] !== null ? round((float) $attendance['avg_rate'], 2) : 0;

        // Ratings for the month
        $ratings = $db->selectOne(
            "SELECT AVG(rating) AS avg_rating, COUNT(*) AS total_count
             FROM coach_ratings
             WHERE coach_id = ? AND status = 'published'
               AND created_at BETWEEN ? AND ?",
            [$coachId, $monthStart . ' 00:00:00', $monthEnd . ' 23:59:59']
        );
        $avgRating = $ratings['avg_rating'] !== null ? round((float) $ratings['avg_rating'], 2) : null;
        $totalRatingsCount = (int) ($ratings['total_count'] ?? 0);

        // Total unique players trained
        $players = $db->selectOne(
            "SELECT COUNT(DISTINCT sa.player_id) AS total_players
             FROM session_attendance sa
             INNER JOIN training_sessions ts ON ts.id = sa.session_id
             WHERE ts.coach_id = ? AND ts.session_date BETWEEN ? AND ?",
            [$coachId, $monthStart, $monthEnd]
        );
        $totalPlayersTrained = (int) ($players['total_players'] ?? 0);

        // Punctuality rate (sessions started on time)
        $punctualityRate = $totalAssigned > 0 ? round(($totalConducted / $totalAssigned) * 100, 2) : 0;

        // Revenue generated (from payments linked to sessions)
        $revenue = $db->selectOne(
            "SELECT COALESCE(SUM(cp.amount), 0) AS total_revenue
             FROM coach_payments cp
             WHERE cp.coach_id = ? AND cp.period_month = ?",
            [$coachId, $month]
        );
        $revenueGenerated = (string) ($revenue['total_revenue'] ?? '0.00');

        // Player retention rate (players from last month who are still active)
        $lastMonth = date('Y-m', strtotime($monthStart . ' -1 month'));
        $lastMonthStart = $lastMonth . '-01';
        $lastMonthEnd = date('Y-m-t', strtotime($lastMonthStart));

        $lastMonthPlayers = $db->selectOne(
            "SELECT COUNT(DISTINCT sa.player_id) AS cnt
             FROM session_attendance sa
             INNER JOIN training_sessions ts ON ts.id = sa.session_id
             WHERE ts.coach_id = ? AND ts.session_date BETWEEN ? AND ?",
            [$coachId, $lastMonthStart, $lastMonthEnd]
        );
        $lastMonthCount = (int) ($lastMonthPlayers['cnt'] ?? 0);

        $retentionRate = 0;
        if ($lastMonthCount > 0) {
            $retained = $db->selectOne(
                "SELECT COUNT(DISTINCT sa_curr.player_id) AS cnt
                 FROM session_attendance sa_curr
                 INNER JOIN training_sessions ts_curr ON ts_curr.id = sa_curr.session_id
                 WHERE ts_curr.coach_id = ? AND ts_curr.session_date BETWEEN ? AND ?
                   AND sa_curr.player_id IN (
                       SELECT DISTINCT sa_prev.player_id
                       FROM session_attendance sa_prev
                       INNER JOIN training_sessions ts_prev ON ts_prev.id = sa_prev.session_id
                       WHERE ts_prev.coach_id = ? AND ts_prev.session_date BETWEEN ? AND ?
                   )",
                [$coachId, $monthStart, $monthEnd, $coachId, $lastMonthStart, $lastMonthEnd]
            );
            $retentionRate = round(((int) ($retained['cnt'] ?? 0) / $lastMonthCount) * 100, 2);
        }

        $metrics = [
            'coach_id'                  => $coachId,
            'period_month'              => $month,
            'total_sessions_assigned'   => $totalAssigned,
            'total_sessions_conducted'  => $totalConducted,
            'total_sessions_cancelled'  => $totalCancelled,
            'avg_attendance_rate'       => $avgAttendanceRate,
            'avg_rating'                => $avgRating,
            'total_ratings_count'       => $totalRatingsCount,
            'total_players_trained'     => $totalPlayersTrained,
            'player_retention_rate'     => $retentionRate,
            'punctuality_rate'          => $punctualityRate,
            'revenue_generated'         => $revenueGenerated,
            'calculated_at'             => date('Y-m-d H:i:s'),
        ];

        // Upsert: delete existing, then insert
        $existing = $db->selectOne(
            "SELECT id FROM coach_performance_metrics WHERE coach_id = ? AND period_month = ?",
            [$coachId, $month]
        );

        if ($existing) {
            $db->update('coach_performance_metrics', $metrics, 'id = ?', [(int) $existing['id']]);
        } else {
            $db->insert('coach_performance_metrics', $metrics);
        }

        return $metrics;
    }

    /**
     * Get composite performance score for ranking.
     */
    public static function getCompositeScore(array $metrics): float
    {
        $avgRating = (float) ($metrics['avg_rating'] ?? 0);
        $attendanceRate = (float) ($metrics['avg_attendance_rate'] ?? 0);
        $conductionRate = 0;
        if ((int) ($metrics['total_sessions_assigned'] ?? 0) > 0) {
            $conductionRate = ((int) ($metrics['total_sessions_conducted'] ?? 0) / (int) $metrics['total_sessions_assigned']) * 100;
        }
        $retentionRate = (float) ($metrics['player_retention_rate'] ?? 0);

        // Weighted composite: Rating 40%, Attendance 25%, Conduction 20%, Retention 15%
        $score = ($avgRating / 5 * 100) * 0.40
               + $attendanceRate * 0.25
               + $conductionRate * 0.20
               + $retentionRate * 0.15;

        return round($score, 2);
    }
}
