package services

import (
	"context"
	"fmt"
	"time"

	"github.com/breakpilot/consent-service/internal/models"

	"github.com/google/uuid"
)

// ========================================
// Grade Statistics
// ========================================

// GetStudentGradeAverage calculates the overall grade average for a student
func (s *GradeService) GetStudentGradeAverage(ctx context.Context, studentID, schoolYearID uuid.UUID, semester int) (float64, error) {
	query := `
		SELECT COALESCE(SUM(value * weight) / NULLIF(SUM(weight), 0), 0)
		FROM grades
		WHERE student_id = $1 AND school_year_id = $2 AND semester = $3 AND is_visible = true`

	var average float64
	err := s.db.Pool.QueryRow(ctx, query, studentID, schoolYearID, semester).Scan(&average)
	if err != nil {
		return 0, fmt.Errorf("failed to calculate average: %w", err)
	}

	return average, nil
}

// GetSubjectGradeStatistics gets grade statistics for a subject in a class
func (s *GradeService) GetSubjectGradeStatistics(ctx context.Context, classID, subjectID, schoolYearID uuid.UUID, semester int) (map[string]interface{}, error) {
	query := `
		SELECT
			COUNT(DISTINCT g.student_id) as student_count,
			AVG(g.value) as class_average,
			MIN(g.value) as best_grade,
			MAX(g.value) as worst_grade,
			COUNT(*) as total_grades
		FROM grades g
		JOIN students s ON g.student_id = s.id
		WHERE s.class_id = $1 AND g.subject_id = $2 AND g.school_year_id = $3 AND g.semester = $4 AND g.is_visible = true`

	var studentCount, totalGrades int
	var classAverage, bestGrade, worstGrade float64

	err := s.db.Pool.QueryRow(ctx, query, classID, subjectID, schoolYearID, semester).Scan(
		&studentCount, &classAverage, &bestGrade, &worstGrade, &totalGrades,
	)
	if err != nil {
		return nil, fmt.Errorf("failed to get statistics: %w", err)
	}

	// Grade distribution (for German grades 1-6)
	distributionQuery := `
		SELECT
			COUNT(CASE WHEN value >= 1 AND value < 1.5 THEN 1 END) as grade_1,
			COUNT(CASE WHEN value >= 1.5 AND value < 2.5 THEN 1 END) as grade_2,
			COUNT(CASE WHEN value >= 2.5 AND value < 3.5 THEN 1 END) as grade_3,
			COUNT(CASE WHEN value >= 3.5 AND value < 4.5 THEN 1 END) as grade_4,
			COUNT(CASE WHEN value >= 4.5 AND value < 5.5 THEN 1 END) as grade_5,
			COUNT(CASE WHEN value >= 5.5 THEN 1 END) as grade_6
		FROM grades g
		JOIN students s ON g.student_id = s.id
		WHERE s.class_id = $1 AND g.subject_id = $2 AND g.school_year_id = $3 AND g.semester = $4 AND g.is_visible = true AND g.type IN ('exam', 'test')`

	var g1, g2, g3, g4, g5, g6 int
	err = s.db.Pool.QueryRow(ctx, distributionQuery, classID, subjectID, schoolYearID, semester).Scan(
		&g1, &g2, &g3, &g4, &g5, &g6,
	)
	if err != nil {
		// Non-fatal, continue without distribution
		g1, g2, g3, g4, g5, g6 = 0, 0, 0, 0, 0, 0
	}

	return map[string]interface{}{
		"student_count": studentCount,
		"class_average": classAverage,
		"best_grade":    bestGrade,
		"worst_grade":   worstGrade,
		"total_grades":  totalGrades,
		"distribution": map[string]int{
			"1": g1,
			"2": g2,
			"3": g3,
			"4": g4,
			"5": g5,
			"6": g6,
		},
	}, nil
}

// ========================================
// Grade Comments
// ========================================

// AddGradeComment adds a comment to a grade
func (s *GradeService) AddGradeComment(ctx context.Context, gradeID, teacherID uuid.UUID, comment string, isPrivate bool) (*models.GradeComment, error) {
	gradeComment := &models.GradeComment{
		ID:        uuid.New(),
		GradeID:   gradeID,
		TeacherID: teacherID,
		Comment:   comment,
		IsPrivate: isPrivate,
		CreatedAt: time.Now(),
	}

	query := `
		INSERT INTO grade_comments (id, grade_id, teacher_id, comment, is_private, created_at)
		VALUES ($1, $2, $3, $4, $5, $6)
		RETURNING id`

	err := s.db.Pool.QueryRow(ctx, query,
		gradeComment.ID, gradeComment.GradeID, gradeComment.TeacherID,
		gradeComment.Comment, gradeComment.IsPrivate, gradeComment.CreatedAt,
	).Scan(&gradeComment.ID)

	if err != nil {
		return nil, fmt.Errorf("failed to add grade comment: %w", err)
	}

	return gradeComment, nil
}

// GetGradeComments gets comments for a grade
func (s *GradeService) GetGradeComments(ctx context.Context, gradeID uuid.UUID, includePrivate bool) ([]models.GradeComment, error) {
	query := `
		SELECT id, grade_id, teacher_id, comment, is_private, created_at
		FROM grade_comments
		WHERE grade_id = $1`

	if !includePrivate {
		query += ` AND is_private = false`
	}

	query += ` ORDER BY created_at DESC`

	rows, err := s.db.Pool.Query(ctx, query, gradeID)
	if err != nil {
		return nil, fmt.Errorf("failed to get grade comments: %w", err)
	}
	defer rows.Close()

	var comments []models.GradeComment
	for rows.Next() {
		var comment models.GradeComment
		err := rows.Scan(
			&comment.ID, &comment.GradeID, &comment.TeacherID,
			&comment.Comment, &comment.IsPrivate, &comment.CreatedAt,
		)
		if err != nil {
			return nil, fmt.Errorf("failed to scan grade comment: %w", err)
		}
		comments = append(comments, comment)
	}

	return comments, nil
}

// ========================================
// Parent Notifications
// ========================================

func (s *GradeService) notifyParentsOfNewGrade(ctx context.Context, grade *models.Grade) {
	if s.matrix == nil {
		return
	}

	// Get student info and Matrix room
	var studentFirstName, studentLastName, matrixDMRoom string
	err := s.db.Pool.QueryRow(ctx, `
		SELECT first_name, last_name, matrix_dm_room
		FROM students
		WHERE id = $1`, grade.StudentID).Scan(&studentFirstName, &studentLastName, &matrixDMRoom)
	if err != nil || matrixDMRoom == "" {
		return
	}

	// Get subject name
	var subjectName string
	err = s.db.Pool.QueryRow(ctx, `SELECT name FROM subjects WHERE id = $1`, grade.SubjectID).Scan(&subjectName)
	if err != nil {
		return
	}

	studentName := studentFirstName + " " + studentLastName
	gradeType := s.getGradeTypeDisplayName(grade.Type)

	// Send Matrix notification
	err = s.matrix.SendGradeNotification(ctx, matrixDMRoom, studentName, subjectName, gradeType, grade.Value)
	if err != nil {
		fmt.Printf("Failed to send grade notification: %v\n", err)
	}
}

func (s *GradeService) getGradeTypeDisplayName(gradeType string) string {
	switch gradeType {
	case models.GradeTypeExam:
		return "Klassenarbeit"
	case models.GradeTypeTest:
		return "Test"
	case models.GradeTypeOral:
		return "Mündliche Note"
	case models.GradeTypeHomework:
		return "Hausaufgabe"
	case models.GradeTypeProject:
		return "Projekt"
	case models.GradeTypeParticipation:
		return "Mitarbeit"
	case models.GradeTypeSemester:
		return "Halbjahreszeugnis"
	case models.GradeTypeFinal:
		return "Zeugnisnote"
	default:
		return gradeType
	}
}
