<?php
declare(strict_types=1);

namespace App\Modules\Coaches\Services;

use App\Core\App;
use App\Core\EventBus;

final class CoachPaymentService
{
    /**
     * Calculate payment for a specific coach and period.
     *
     * @param int    $coachId Coach ID
     * @param string $period  YYYY-MM format
     * @return array Payment calculation details
     */
    public static function calculatePayment(int $coachId, string $period): array
    {
        $db = App::getInstance()->db();

        // Get coach details
        $coach = $db->selectOne("SELECT * FROM coaches WHERE id = ? AND is_archived = 0", [$coachId]);
        if (!$coach) {
            return [];
        }

        $paymentModel = $coach['payment_model'] ?? 'per_session';
        $sessionRate = (float) ($coach['session_rate'] ?? 0);
        $monthlyRate = (float) ($coach['monthly_rate'] ?? 0);
        $hourlyRate = (float) ($coach['hourly_rate'] ?? 0);

        // Get sessions for the period
        $periodStart = $period . '-01';
        $periodEnd = date('Y-m-t', strtotime($periodStart));

        $sessions = $db->select(
            "SELECT ts.id, ts.session_date, ts.status,
                    (SELECT COUNT(*) FROM session_attendance sa WHERE sa.session_id = ts.id AND sa.status = 'present') AS players_attended
             FROM training_sessions ts
             WHERE ts.coach_id = ?
               AND ts.session_date BETWEEN ? AND ?
               AND ts.status = 'completed'
             ORDER BY ts.session_date ASC",
            [$coachId, $periodStart, $periodEnd]
        );

        $sessionsConducted = count($sessions);
        $totalPlayersServed = 0;
        foreach ($sessions as $s) {
            $totalPlayersServed += (int) $s['players_attended'];
        }

        $baseAmount = 0.0;
        $bonus = 0.0;
        $deductions = 0.0;
        $calculationDetails = [];

        switch ($paymentModel) {
            case 'per_session':
                $baseAmount = $sessionsConducted * $sessionRate;
                $calculationDetails = [
                    'model' => 'per_session',
                    'sessions' => $sessionsConducted,
                    'rate_per_session' => $sessionRate,
                    'formula' => "{$sessionsConducted} sessions x {$sessionRate} EGP",
                ];
                break;

            case 'per_player':
                $perPlayerRate = $hourlyRate > 0 ? $hourlyRate : $sessionRate;
                $baseAmount = $totalPlayersServed * $perPlayerRate;
                $calculationDetails = [
                    'model' => 'per_player',
                    'total_players' => $totalPlayersServed,
                    'rate_per_player' => $perPlayerRate,
                    'formula' => "{$totalPlayersServed} players x {$perPlayerRate} EGP",
                ];
                break;

            case 'monthly_fixed':
                $baseAmount = $monthlyRate;
                $calculationDetails = [
                    'model' => 'monthly_fixed',
                    'monthly_rate' => $monthlyRate,
                    'formula' => "Fixed monthly: {$monthlyRate} EGP",
                ];
                break;

            case 'hybrid':
                $baseAmount = $monthlyRate;
                // Bonus for sessions over a threshold (e.g., 20 sessions/month)
                $sessionThreshold = 20;
                $extraSessions = max(0, $sessionsConducted - $sessionThreshold);
                $bonus = $extraSessions * $sessionRate;
                $calculationDetails = [
                    'model' => 'hybrid',
                    'base_monthly' => $monthlyRate,
                    'session_threshold' => $sessionThreshold,
                    'extra_sessions' => $extraSessions,
                    'bonus_rate' => $sessionRate,
                    'formula' => "Base {$monthlyRate} + ({$extraSessions} extra sessions x {$sessionRate})",
                ];
                break;
        }

        $netAmount = $baseAmount + $bonus - $deductions;

        return [
            'sessions_conducted'   => $sessionsConducted,
            'total_players_served' => $totalPlayersServed,
            'base_amount'          => round($baseAmount, 2),
            'bonus'                => round($bonus, 2),
            'deductions'           => round($deductions, 2),
            'net_amount'           => round($netAmount, 2),
            'calculation_json'     => $calculationDetails,
        ];
    }

    /**
     * Generate monthly payments for all active coaches.
     *
     * @param string $period YYYY-MM format
     * @return int Number of payments generated
     */
    public static function generateMonthlyPayments(string $period): int
    {
        $db = App::getInstance()->db();

        $coaches = $db->select(
            "SELECT id, payment_model FROM coaches WHERE is_active = 1 AND is_archived = 0"
        );

        $count = 0;
        foreach ($coaches as $coach) {
            $coachId = (int) $coach['id'];

            // Skip if already generated for this period
            $existing = $db->selectOne(
                "SELECT id FROM coach_payments WHERE coach_id = ? AND payment_period = ?",
                [$coachId, $period]
            );
            if ($existing) {
                continue;
            }

            $calc = self::calculatePayment($coachId, $period);
            if (empty($calc)) {
                continue;
            }

            $db->insert('coach_payments', [
                'coach_id'             => $coachId,
                'payment_period'       => $period,
                'payment_model'        => $coach['payment_model'] ?? 'per_session',
                'sessions_conducted'   => $calc['sessions_conducted'],
                'total_players_served' => $calc['total_players_served'],
                'base_amount'          => $calc['base_amount'],
                'bonus'                => $calc['bonus'],
                'deductions'           => $calc['deductions'],
                'net_amount'           => $calc['net_amount'],
                'calculation_json'     => json_encode($calc['calculation_json'], JSON_UNESCAPED_UNICODE),
                'status'               => 'draft',
            ]);

            $count++;
        }

        return $count;
    }

    /**
     * Approve a coach payment.
     */
    public static function approvePayment(int $paymentId, int $approvedBy): void
    {
        $db = App::getInstance()->db();

        $payment = $db->selectOne("SELECT * FROM coach_payments WHERE id = ?", [$paymentId]);
        if (!$payment || $payment['status'] !== 'draft') {
            return;
        }

        $db->update('coach_payments', [
            'status'      => 'approved',
            'approved_by' => $approvedBy,
            'approved_at' => date('Y-m-d H:i:s'),
        ], 'id = ?', [$paymentId]);

        EventBus::dispatch('coach.payment.approved', [
            'payment_id' => $paymentId,
            'coach_id'   => (int) $payment['coach_id'],
            'period'     => $payment['payment_period'],
            'net_amount' => (float) $payment['net_amount'],
            'approved_by' => $approvedBy,
        ]);
    }
}
