package services

import (
	"context"
	"fmt"
	"time"

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

	"github.com/google/uuid"
)

// ========================================
// Absence Reports (Parent-initiated)
// ========================================

// ReportAbsence allows parents to report a student's absence
func (s *AttendanceService) ReportAbsence(ctx context.Context, req models.ReportAbsenceRequest, reportedByUserID uuid.UUID) (*models.AbsenceReport, error) {
	studentID, err := uuid.Parse(req.StudentID)
	if err != nil {
		return nil, fmt.Errorf("invalid student ID: %w", err)
	}

	startDate, err := time.Parse("2006-01-02", req.StartDate)
	if err != nil {
		return nil, fmt.Errorf("invalid start date format: %w", err)
	}

	endDate, err := time.Parse("2006-01-02", req.EndDate)
	if err != nil {
		return nil, fmt.Errorf("invalid end date format: %w", err)
	}

	report := &models.AbsenceReport{
		ID:             uuid.New(),
		StudentID:      studentID,
		StartDate:      startDate,
		EndDate:        endDate,
		Reason:         req.Reason,
		ReasonCategory: req.ReasonCategory,
		Status:         "reported",
		ReportedBy:     reportedByUserID,
		ReportedAt:     time.Now(),
		CreatedAt:      time.Now(),
		UpdatedAt:      time.Now(),
	}

	query := `
		INSERT INTO absence_reports (id, student_id, start_date, end_date, reason, reason_category, status, reported_by, reported_at, created_at, updated_at)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
		RETURNING id`

	err = s.db.Pool.QueryRow(ctx, query,
		report.ID, report.StudentID, report.StartDate, report.EndDate,
		report.Reason, report.ReasonCategory, report.Status,
		report.ReportedBy, report.ReportedAt, report.CreatedAt, report.UpdatedAt,
	).Scan(&report.ID)

	if err != nil {
		return nil, fmt.Errorf("failed to create absence report: %w", err)
	}

	return report, nil
}

// ConfirmAbsence allows teachers to confirm/excuse an absence
func (s *AttendanceService) ConfirmAbsence(ctx context.Context, reportID uuid.UUID, confirmedByUserID uuid.UUID, status string) error {
	query := `
		UPDATE absence_reports
		SET status = $1, confirmed_by = $2, confirmed_at = NOW(), updated_at = NOW()
		WHERE id = $3`

	result, err := s.db.Pool.Exec(ctx, query, status, confirmedByUserID, reportID)
	if err != nil {
		return fmt.Errorf("failed to confirm absence: %w", err)
	}

	if result.RowsAffected() == 0 {
		return fmt.Errorf("absence report not found")
	}

	return nil
}

// GetAbsenceReports gets absence reports for a student
func (s *AttendanceService) GetAbsenceReports(ctx context.Context, studentID uuid.UUID) ([]models.AbsenceReport, error) {
	query := `
		SELECT id, student_id, start_date, end_date, reason, reason_category, status, reported_by, reported_at, confirmed_by, confirmed_at, medical_certificate, certificate_uploaded, matrix_notification_sent, email_notification_sent, created_at, updated_at
		FROM absence_reports
		WHERE student_id = $1
		ORDER BY start_date DESC`

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

	var reports []models.AbsenceReport
	for rows.Next() {
		var report models.AbsenceReport
		err := rows.Scan(
			&report.ID, &report.StudentID, &report.StartDate, &report.EndDate,
			&report.Reason, &report.ReasonCategory, &report.Status,
			&report.ReportedBy, &report.ReportedAt, &report.ConfirmedBy, &report.ConfirmedAt,
			&report.MedicalCertificate, &report.CertificateUploaded,
			&report.MatrixNotificationSent, &report.EmailNotificationSent,
			&report.CreatedAt, &report.UpdatedAt,
		)
		if err != nil {
			return nil, fmt.Errorf("failed to scan absence report: %w", err)
		}
		reports = append(reports, report)
	}

	return reports, nil
}

// GetPendingAbsenceReports gets all unconfirmed absence reports for a class
func (s *AttendanceService) GetPendingAbsenceReports(ctx context.Context, classID uuid.UUID) ([]models.AbsenceReport, error) {
	query := `
		SELECT ar.id, ar.student_id, ar.start_date, ar.end_date, ar.reason, ar.reason_category, ar.status, ar.reported_by, ar.reported_at, ar.confirmed_by, ar.confirmed_at, ar.medical_certificate, ar.certificate_uploaded, ar.matrix_notification_sent, ar.email_notification_sent, ar.created_at, ar.updated_at
		FROM absence_reports ar
		JOIN students s ON ar.student_id = s.id
		WHERE s.class_id = $1 AND ar.status = 'reported'
		ORDER BY ar.start_date DESC`

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

	var reports []models.AbsenceReport
	for rows.Next() {
		var report models.AbsenceReport
		err := rows.Scan(
			&report.ID, &report.StudentID, &report.StartDate, &report.EndDate,
			&report.Reason, &report.ReasonCategory, &report.Status,
			&report.ReportedBy, &report.ReportedAt, &report.ConfirmedBy, &report.ConfirmedAt,
			&report.MedicalCertificate, &report.CertificateUploaded,
			&report.MatrixNotificationSent, &report.EmailNotificationSent,
			&report.CreatedAt, &report.UpdatedAt,
		)
		if err != nil {
			return nil, fmt.Errorf("failed to scan absence report: %w", err)
		}
		reports = append(reports, report)
	}

	return reports, nil
}

// ========================================
// Attendance Statistics
// ========================================

// GetStudentAttendanceStats gets attendance statistics for a student
func (s *AttendanceService) GetStudentAttendanceStats(ctx context.Context, studentID uuid.UUID, schoolYearID uuid.UUID) (map[string]interface{}, error) {
	query := `
		SELECT
			COUNT(*) as total_records,
			COUNT(CASE WHEN status = 'present' THEN 1 END) as present_count,
			COUNT(CASE WHEN status IN ('absent', 'excused', 'unexcused', 'pending_confirmation') THEN 1 END) as absent_count,
			COUNT(CASE WHEN status = 'unexcused' THEN 1 END) as unexcused_count,
			COUNT(CASE WHEN status IN ('late', 'late_excused') THEN 1 END) as late_count
		FROM attendance_records ar
		JOIN timetable_slots ts ON ar.slot_id = ts.id
		JOIN schools sch ON ts.school_id = sch.id
		JOIN school_years sy ON sy.school_id = sch.id AND sy.id = $2
		WHERE ar.student_id = $1 AND ar.date >= sy.start_date AND ar.date <= sy.end_date`

	var totalRecords, presentCount, absentCount, unexcusedCount, lateCount int
	err := s.db.Pool.QueryRow(ctx, query, studentID, schoolYearID).Scan(
		&totalRecords, &presentCount, &absentCount, &unexcusedCount, &lateCount,
	)
	if err != nil {
		return nil, fmt.Errorf("failed to get attendance stats: %w", err)
	}

	var attendanceRate float64
	if totalRecords > 0 {
		attendanceRate = float64(presentCount) / float64(totalRecords) * 100
	}

	return map[string]interface{}{
		"total_records":   totalRecords,
		"present_count":   presentCount,
		"absent_count":    absentCount,
		"unexcused_count": unexcusedCount,
		"late_count":      lateCount,
		"attendance_rate": attendanceRate,
	}, nil
}

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

func (s *AttendanceService) notifyParentsOfAbsence(ctx context.Context, record *models.AttendanceRecord) {
	if s.matrix == nil {
		return
	}

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

	// Get slot info
	var slotNumber int
	err = s.db.Pool.QueryRow(ctx, `SELECT slot_number FROM timetable_slots WHERE id = $1`, record.SlotID).Scan(&slotNumber)
	if err != nil {
		return
	}

	studentName := studentFirstName + " " + studentLastName
	dateStr := record.Date.Format("02.01.2006")

	// Send Matrix notification
	err = s.matrix.SendAbsenceNotification(ctx, matrixDMRoom, studentName, dateStr, slotNumber)
	if err != nil {
		fmt.Printf("Failed to send absence notification: %v\n", err)
		return
	}

	// Update notification status
	s.db.Pool.Exec(ctx, `
		UPDATE attendance_records
		SET updated_at = NOW()
		WHERE id = $1`, record.ID)

	// Log the notification
	s.createAbsenceNotificationLog(ctx, record.ID, studentName, dateStr, slotNumber)
}

func (s *AttendanceService) notifyParentsOfAbsenceByStudentID(ctx context.Context, studentID uuid.UUID, date time.Time, slotID uuid.UUID) {
	record := &models.AttendanceRecord{
		StudentID: studentID,
		Date:      date,
		SlotID:    slotID,
	}
	s.notifyParentsOfAbsence(ctx, record)
}

func (s *AttendanceService) createAbsenceNotificationLog(ctx context.Context, recordID uuid.UUID, studentName, dateStr string, slotNumber int) {
	// Get parent IDs for this student
	query := `
		SELECT p.id
		FROM parents p
		JOIN student_parents sp ON p.id = sp.parent_id
		JOIN attendance_records ar ON sp.student_id = ar.student_id
		WHERE ar.id = $1`

	rows, err := s.db.Pool.Query(ctx, query, recordID)
	if err != nil {
		return
	}
	defer rows.Close()

	message := fmt.Sprintf("Abwesenheitsmeldung: %s war am %s in der %d. Stunde nicht anwesend.", studentName, dateStr, slotNumber)

	for rows.Next() {
		var parentID uuid.UUID
		if err := rows.Scan(&parentID); err != nil {
			continue
		}

		// Insert notification log
		s.db.Pool.Exec(ctx, `
			INSERT INTO absence_notifications (id, attendance_record_id, parent_id, channel, message_content, sent_at, created_at)
			VALUES ($1, $2, $3, 'matrix', $4, NOW(), NOW())`,
			uuid.New(), recordID, parentID, message)
	}
}
