<?php
declare(strict_types=1);

require_once __DIR__ . '/db.php';
require_once __DIR__ . '/functions.php';
require_once __DIR__ . '/student-course-context.php';

if (!function_exists('resolveStudentCourseId')) {
    function resolveStudentCourseId(PDO $pdo, int $studentId, int $preferredCourseId = 0): int
    {
        if ($preferredCourseId > 0 && isStudentEnrolledInCourse($pdo, $studentId, $preferredCourseId)) return $preferredCourseId;
        $sessionCourse = (int)($_SESSION['selected_core_course_id'] ?? 0);
        if ($sessionCourse > 0 && isStudentEnrolledInCourse($pdo, $studentId, $sessionCourse)) return $sessionCourse;
        $row = safeFetch($pdo,
            "SELECT course_id FROM core_course_students
             WHERE student_id = ? AND status IN ('active','completed')
             ORDER BY status='active' DESC, COALESCE(updated_at,joined_at,created_at) DESC, id DESC LIMIT 1",
            [$studentId]
        );
        return (int)($row['course_id'] ?? 0);
    }
}

if (!function_exists('calculateWeightedGrade')) {
    function calculateWeightedGrade(array $items): float
    {
        if ($items === []) return 0.0;
        $weightedSum = 0.0;
        $weightSum = 0.0;
        $plainSum = 0.0;
        $plainCount = 0;
        foreach ($items as $item) {
            $score = (float)($item['score'] ?? $item['points_awarded'] ?? 0);
            $max = max(0.0001, (float)($item['max_score'] ?? $item['max_points'] ?? $item['points'] ?? 100));
            $pct = isset($item['percentage']) && $item['percentage'] !== null
                ? max(0.0, min(100.0, (float)$item['percentage']))
                : max(0.0, min(100.0, ($score / $max) * 100));
            $weight = max(0.0, (float)($item['weight'] ?? $item['weight_percent'] ?? $item['weight_percentage'] ?? 0));
            if ($weight > 0) {
                $weightedSum += $pct * $weight;
                $weightSum += $weight;
            } else {
                $plainSum += $pct;
                $plainCount++;
            }
        }
        if ($weightSum > 0) {
            $weightedAverage = $weightedSum / $weightSum;
            if ($plainCount === 0) return round($weightedAverage, 2);
            return round(($weightedAverage + ($plainSum / $plainCount)) / 2, 2);
        }
        return $plainCount > 0 ? round($plainSum / $plainCount, 2) : 0.0;
    }
}

if (!function_exists('ensureGradeItemDefinition')) {
    function ensureGradeItemDefinition(PDO $pdo, int $courseId, string $itemType, int $itemId, string $title, float $maxScore, float $weight, ?int $teacherId = null, ?int $adminId = null): int
    {
        if ($courseId <= 0 || !tableExists($pdo, 'core_grade_items')) return 0;
        $itemType = strtolower(trim($itemType)) ?: 'extra';
        $query = 'SELECT id FROM core_grade_items WHERE course_id = ? AND COALESCE(item_type,type) = ?';
        $params = [$courseId, $itemType];
        if ($itemId > 0 && columnExists($pdo, 'core_grade_items', 'item_id')) {
            $query .= ' AND item_id = ?';
            $params[] = $itemId;
        } else {
            $query .= ' AND title = ?';
            $params[] = $title;
        }
        $query .= ' ORDER BY id DESC LIMIT 1';
        $existing = safeFetch($pdo, $query, $params);
        if ($existing) return (int)$existing['id'];

        $columns = ['course_id','title','item_type','type','weight_percent','weight','max_points','max_score','status','created_at'];
        $values = [$courseId,$title,$itemType,$itemType,$weight,$weight,$maxScore,$maxScore,'active',now()];
        if ($itemId > 0 && columnExists($pdo, 'core_grade_items', 'item_id')) { $columns[]='item_id'; $values[]=$itemId; }
        if ($itemType === 'exam' && $itemId > 0 && columnExists($pdo, 'core_grade_items', 'exam_id')) { $columns[]='exam_id'; $values[]=$itemId; }
        if ($teacherId && columnExists($pdo, 'core_grade_items', 'teacher_id')) { $columns[]='teacher_id'; $values[]=$teacherId; }
        if ($adminId && columnExists($pdo, 'core_grade_items', 'created_by_admin_id')) { $columns[]='created_by_admin_id'; $values[]=$adminId; }
        $sql = 'INSERT INTO core_grade_items (`' . implode('`,`', $columns) . '`) VALUES (' . implode(',', array_fill(0,count($columns),'?')) . ')';
        $stmt = $pdo->prepare($sql);
        $stmt->execute($values);
        return (int)$pdo->lastInsertId();
    }
}

if (!function_exists('saveStudentGrade')) {
    function saveStudentGrade(PDO $pdo, int $studentId, int $courseId, string $itemType, int $itemId, string $title, float $score, float $maxScore = 100, float $weight = 0, ?string $feedback = null, ?int $teacherId = null, ?int $adminId = null): bool
    {
        $courseId = resolveStudentCourseId($pdo, $studentId, $courseId);
        if ($studentId <= 0 || $courseId <= 0 || !isStudentEnrolledInCourse($pdo, $studentId, $courseId)) return false;
        $maxScore = max(0.01, $maxScore);
        $score = max(0.0, min($maxScore, $score));
        $percentage = round(($score / $maxScore) * 100, 2);
        $gradeItemId = ensureGradeItemDefinition($pdo, $courseId, $itemType, $itemId, $title, $maxScore, $weight, $teacherId, $adminId);
        if ($gradeItemId <= 0) return false;

        if (tableExists($pdo, 'core_grades')) {
            $stmt = $pdo->prepare(
                'INSERT INTO core_grades (grade_item_id,student_id,course_id,score,max_score,percentage,feedback,graded_by_teacher_id,graded_by_admin_id,created_at,updated_at)
                 VALUES (?,?,?,?,?,?,?,?,?,NOW(),NOW())
                 ON DUPLICATE KEY UPDATE score=VALUES(score),max_score=VALUES(max_score),percentage=VALUES(percentage),feedback=VALUES(feedback),graded_by_teacher_id=VALUES(graded_by_teacher_id),graded_by_admin_id=VALUES(graded_by_admin_id),updated_at=NOW()'
            );
            $ok = $stmt->execute([$gradeItemId,$studentId,$courseId,$score,$maxScore,$percentage,$feedback,$teacherId,$adminId]);
        } else {
            $stmt = $pdo->prepare('UPDATE core_grade_items SET student_id=?,score=?,max_score=?,percentage=?,feedback=?,notes=?,updated_at=NOW() WHERE id=?');
            $ok = $stmt->execute([$studentId,$score,$maxScore,$percentage,$feedback,$feedback,$gradeItemId]);
        }
        recalculateFinalGrade($pdo, $studentId, $courseId);
        return $ok;
    }
}

if (!function_exists('upsertGradeItem')) {
    function upsertGradeItem(PDO $pdo, int $studentId, int $courseId, string $itemType, int $itemId, string $title, float $score, float $maxScore, float $weight = 0, ?string $feedback = null): bool
    {
        return saveStudentGrade($pdo,$studentId,$courseId,$itemType,$itemId,$title,$score,$maxScore,$weight,$feedback,function_exists('currentTeacherId') ? currentTeacherId() : null,function_exists('currentAdminId') ? (currentAdminId() ?: null) : null);
    }
}

if (!function_exists('loadStudentGradeRows')) {
    function loadStudentGradeRows(PDO $pdo, int $studentId, int $courseId): array
    {
        if (tableExists($pdo, 'core_grades')) {
            return safeFetchAll($pdo,
                "SELECT g.*, gi.title, COALESCE(NULLIF(gi.item_type,''),gi.type,'extra') AS item_type,
                        COALESCE(NULLIF(gi.weight,0),gi.weight_percent,0) AS weight
                 FROM core_grades g INNER JOIN core_grade_items gi ON gi.id=g.grade_item_id
                 WHERE g.student_id=? AND g.course_id=? AND COALESCE(gi.status,'active')='active'",
                [$studentId,$courseId]
            );
        }
        return safeFetchAll($pdo,
            "SELECT *, COALESCE(NULLIF(item_type,''),type,'extra') AS item_type,
                    COALESCE(NULLIF(weight,0),weight_percent,0) AS weight
             FROM core_grade_items WHERE student_id=? AND course_id=? AND COALESCE(status,'active')='active'",
            [$studentId,$courseId]
        );
    }
}

if (!function_exists('recalculateFinalGrade')) {
    function recalculateFinalGrade(PDO $pdo, int $studentId, int $courseId): array
    {
        $result = ['final_percentage'=>0.0,'percentage'=>0.0,'grade_letter'=>'F','letter'=>'F','gpa'=>0.0,'pass_status'=>'failed'];
        if ($studentId <= 0 || $courseId <= 0) return $result;
        $rows = loadStudentGradeRows($pdo,$studentId,$courseId);
        $percentage = calculateWeightedGrade($rows);
        $letter = gradeLetter($percentage);
        $gpa = gradeGpa($percentage);
        $pass = getPassStatus($percentage);

        $components = ['exam'=>0,'homework'=>0,'participation'=>0,'attendance'=>0,'shadowing'=>0,'obstacle'=>0,'vocabulary'=>0,'extra'=>0];
        foreach ($components as $type => $_) {
            $group = array_values(array_filter($rows, fn(array $r): bool => strtolower((string)($r['item_type'] ?? '')) === $type || ($type==='obstacle' && strtolower((string)($r['item_type'] ?? ''))==='obstacles')));
            $components[$type] = $group ? calculateWeightedGrade($group) : 0.0;
        }

        if (tableExists($pdo,'core_final_grades')) {
            $stmt = $pdo->prepare(
                "INSERT INTO core_final_grades
                 (course_id,student_id,exams_score,homework_score,participation_score,attendance_score,shadowing_score,obstacles_score,vocabulary_score,extra_score,final_percentage,grade_letter,gpa,pass_status,status,calculated_at,created_at,updated_at)
                 VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,'draft',NOW(),NOW(),NOW())
                 ON DUPLICATE KEY UPDATE exams_score=VALUES(exams_score),homework_score=VALUES(homework_score),participation_score=VALUES(participation_score),attendance_score=VALUES(attendance_score),shadowing_score=VALUES(shadowing_score),obstacles_score=VALUES(obstacles_score),vocabulary_score=VALUES(vocabulary_score),extra_score=VALUES(extra_score),final_percentage=VALUES(final_percentage),grade_letter=VALUES(grade_letter),gpa=VALUES(gpa),pass_status=VALUES(pass_status),calculated_at=NOW(),updated_at=NOW()"
            );
            $stmt->execute([$courseId,$studentId,$components['exam'],$components['homework'],$components['participation'],$components['attendance'],$components['shadowing'],$components['obstacle'],$components['vocabulary'],$components['extra'],$percentage,$letter,$gpa,$pass]);
        }
        return ['final_percentage'=>$percentage,'percentage'=>$percentage,'grade_letter'=>$letter,'letter'=>$letter,'gpa'=>$gpa,'pass_status'=>$pass] + $components;
    }
}

if (!function_exists('calculateStudentFinalGrade')) {
    function calculateStudentFinalGrade(PDO $pdo, int $studentId, int $courseId = 0): float
    {
        $courseId = resolveStudentCourseId($pdo,$studentId,$courseId);
        return (float)(recalculateFinalGrade($pdo,$studentId,$courseId)['final_percentage'] ?? 0);
    }
}

if (!function_exists('getFinalGrade')) {
    function getFinalGrade(PDO $pdo, int $studentId, int $courseId): array
    {
        $row = safeFetch($pdo,'SELECT * FROM core_final_grades WHERE student_id=? AND course_id=? LIMIT 1',[$studentId,$courseId]);
        return $row ?: recalculateFinalGrade($pdo,$studentId,$courseId);
    }
}
if (!function_exists('getStudentFinalGrade')) {
    function getStudentFinalGrade(PDO $pdo, int $studentId, int $courseId = 0): array
    {
        $courseId = resolveStudentCourseId($pdo,$studentId,$courseId);
        return getFinalGrade($pdo,$studentId,$courseId);
    }
}
