package services

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/breakpilot/school-service/internal/models"
	"github.com/jackc/pgx/v5/pgxpool"
)

// CertificateService handles certificate-related operations
type CertificateService struct {
	db              *pgxpool.Pool
	gradeService    *GradeService
	gradebookService *GradebookService
}

// NewCertificateService creates a new CertificateService
func NewCertificateService(db *pgxpool.Pool, gradeService *GradeService, gradebookService *GradebookService) *CertificateService {
	return &CertificateService{
		db:               db,
		gradeService:     gradeService,
		gradebookService: gradebookService,
	}
}

// CertificateTemplate represents a certificate template
type CertificateTemplate struct {
	Name        string `json:"name"`
	FederalState string `json:"federal_state"`
	SchoolType  string `json:"school_type"`
	GradeLevel  string `json:"grade_level"` // "1-4", "5-10", "11-13"
	TemplatePath string `json:"template_path"`
}

// GetAvailableTemplates returns available certificate templates
func (s *CertificateService) GetAvailableTemplates() []CertificateTemplate {
	// In a real implementation, these would be loaded from a templates directory
	return []CertificateTemplate{
		{Name: "Halbjahreszeugnis Grundschule", FederalState: "generic", SchoolType: "grundschule", GradeLevel: "1-4", TemplatePath: "generic/grundschule_halbjahr.html"},
		{Name: "Jahreszeugnis Grundschule", FederalState: "generic", SchoolType: "grundschule", GradeLevel: "1-4", TemplatePath: "generic/grundschule_jahr.html"},
		{Name: "Halbjahreszeugnis Sek I", FederalState: "generic", SchoolType: "sek1", GradeLevel: "5-10", TemplatePath: "generic/sek1_halbjahr.html"},
		{Name: "Jahreszeugnis Sek I", FederalState: "generic", SchoolType: "sek1", GradeLevel: "5-10", TemplatePath: "generic/sek1_jahr.html"},
		{Name: "Halbjahreszeugnis Sek II", FederalState: "generic", SchoolType: "sek2", GradeLevel: "11-13", TemplatePath: "generic/sek2_halbjahr.html"},
		{Name: "Abiturzeugnis", FederalState: "generic", SchoolType: "sek2", GradeLevel: "11-13", TemplatePath: "generic/abitur.html"},
		// Niedersachsen specific
		{Name: "Halbjahreszeugnis Gymnasium (NI)", FederalState: "niedersachsen", SchoolType: "gymnasium", GradeLevel: "5-10", TemplatePath: "niedersachsen/gymnasium_halbjahr.html"},
		// NRW specific
		{Name: "Halbjahreszeugnis Gymnasium (NRW)", FederalState: "nrw", SchoolType: "gymnasium", GradeLevel: "5-10", TemplatePath: "nrw/gymnasium_halbjahr.html"},
	}
}

// GenerateCertificate generates a certificate for a student
func (s *CertificateService) GenerateCertificate(ctx context.Context, req *models.GenerateCertificateRequest) (*models.Certificate, error) {
	// Get student grades
	grades, err := s.gradeService.GetStudentGrades(ctx, req.StudentID)
	if err != nil {
		return nil, fmt.Errorf("failed to get student grades: %w", err)
	}

	// Filter grades for the requested school year and semester
	var relevantGrades []models.GradeOverview
	for _, g := range grades {
		if g.SchoolYearID.String() == req.SchoolYearID && g.Semester == req.Semester {
			relevantGrades = append(relevantGrades, g)
		}
	}

	// Get attendance summary
	excusedDays, unexcusedDays, err := s.gradebookService.GetAttendanceSummary(ctx, req.StudentID, req.SchoolYearID)
	if err != nil {
		// Non-fatal, continue with zero absences
		excusedDays, unexcusedDays = 0, 0
	}

	// Build grades JSON
	gradesMap := make(map[string]interface{})
	for _, g := range relevantGrades {
		gradesMap[g.SubjectName] = map[string]interface{}{
			"written_avg":  g.WrittenGradeAvg,
			"oral":         g.OralGrade,
			"final":        g.FinalGrade,
			"final_locked": g.FinalGradeLocked,
		}
	}

	gradesJSON, _ := json.Marshal(gradesMap)

	// Create certificate record
	var certificate models.Certificate
	err = s.db.QueryRow(ctx, `
		INSERT INTO certificates (student_id, school_year_id, semester, certificate_type, template_name, grades_json, remarks, absence_days, absence_days_unexcused, status)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, 'draft')
		RETURNING id, student_id, school_year_id, semester, certificate_type, template_name, grades_json, remarks, absence_days, absence_days_unexcused, generated_pdf_path, status, created_at, updated_at
	`, req.StudentID, req.SchoolYearID, req.Semester, req.CertificateType, req.TemplateName, gradesJSON, req.Remarks, excusedDays+unexcusedDays, unexcusedDays).Scan(
		&certificate.ID, &certificate.StudentID, &certificate.SchoolYearID, &certificate.Semester, &certificate.CertificateType, &certificate.TemplateName, &certificate.GradesJSON, &certificate.Remarks, &certificate.AbsenceDays, &certificate.AbsenceDaysUnexcused, &certificate.GeneratedPDFPath, &certificate.Status, &certificate.CreatedAt, &certificate.UpdatedAt,
	)
	if err != nil {
		return nil, err
	}

	return &certificate, nil
}

// GetCertificates returns certificates for a class
func (s *CertificateService) GetCertificates(ctx context.Context, classID string, semester int) ([]models.Certificate, error) {
	rows, err := s.db.Query(ctx, `
		SELECT c.id, c.student_id, c.school_year_id, c.semester, c.certificate_type, c.template_name, c.grades_json, c.remarks, c.absence_days, c.absence_days_unexcused, c.generated_pdf_path, c.status, c.created_at, c.updated_at,
		       CONCAT(st.first_name, ' ', st.last_name) as student_name,
		       cl.name as class_name
		FROM certificates c
		JOIN students st ON c.student_id = st.id
		JOIN classes cl ON st.class_id = cl.id
		WHERE cl.id = $1 AND c.semester = $2
		ORDER BY st.last_name, st.first_name
	`, classID, semester)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var certificates []models.Certificate
	for rows.Next() {
		var cert models.Certificate
		if err := rows.Scan(&cert.ID, &cert.StudentID, &cert.SchoolYearID, &cert.Semester, &cert.CertificateType, &cert.TemplateName, &cert.GradesJSON, &cert.Remarks, &cert.AbsenceDays, &cert.AbsenceDaysUnexcused, &cert.GeneratedPDFPath, &cert.Status, &cert.CreatedAt, &cert.UpdatedAt, &cert.StudentName, &cert.ClassName); err != nil {
			return nil, err
		}
		certificates = append(certificates, cert)
	}
	return certificates, nil
}

// GetCertificate returns a single certificate
func (s *CertificateService) GetCertificate(ctx context.Context, certificateID string) (*models.Certificate, error) {
	var cert models.Certificate
	err := s.db.QueryRow(ctx, `
		SELECT c.id, c.student_id, c.school_year_id, c.semester, c.certificate_type, c.template_name, c.grades_json, c.remarks, c.absence_days, c.absence_days_unexcused, c.generated_pdf_path, c.status, c.created_at, c.updated_at,
		       CONCAT(st.first_name, ' ', st.last_name) as student_name,
		       cl.name as class_name
		FROM certificates c
		JOIN students st ON c.student_id = st.id
		JOIN classes cl ON st.class_id = cl.id
		WHERE c.id = $1
	`, certificateID).Scan(
		&cert.ID, &cert.StudentID, &cert.SchoolYearID, &cert.Semester, &cert.CertificateType, &cert.TemplateName, &cert.GradesJSON, &cert.Remarks, &cert.AbsenceDays, &cert.AbsenceDaysUnexcused, &cert.GeneratedPDFPath, &cert.Status, &cert.CreatedAt, &cert.UpdatedAt, &cert.StudentName, &cert.ClassName,
	)
	return &cert, err
}

// UpdateCertificate updates a certificate
func (s *CertificateService) UpdateCertificate(ctx context.Context, certificateID string, remarks string) (*models.Certificate, error) {
	var cert models.Certificate
	err := s.db.QueryRow(ctx, `
		UPDATE certificates SET remarks = $2, updated_at = NOW()
		WHERE id = $1
		RETURNING id, student_id, school_year_id, semester, certificate_type, template_name, grades_json, remarks, absence_days, absence_days_unexcused, generated_pdf_path, status, created_at, updated_at
	`, certificateID, remarks).Scan(
		&cert.ID, &cert.StudentID, &cert.SchoolYearID, &cert.Semester, &cert.CertificateType, &cert.TemplateName, &cert.GradesJSON, &cert.Remarks, &cert.AbsenceDays, &cert.AbsenceDaysUnexcused, &cert.GeneratedPDFPath, &cert.Status, &cert.CreatedAt, &cert.UpdatedAt,
	)
	return &cert, err
}

// FinalizeCertificate finalizes a certificate (prevents further changes)
func (s *CertificateService) FinalizeCertificate(ctx context.Context, certificateID string) error {
	_, err := s.db.Exec(ctx, `
		UPDATE certificates SET status = 'final', updated_at = NOW()
		WHERE id = $1
	`, certificateID)
	return err
}

// GeneratePDF generates a PDF for a certificate
// In a real implementation, this would use a PDF generation library
func (s *CertificateService) GeneratePDF(ctx context.Context, certificateID string) ([]byte, error) {
	cert, err := s.GetCertificate(ctx, certificateID)
	if err != nil {
		return nil, err
	}

	// Placeholder: In reality, this would:
	// 1. Load the HTML template
	// 2. Fill in student data, grades, attendance
	// 3. Convert to PDF using a library like wkhtmltopdf or chromedp

	// For now, return a simple text representation
	content := fmt.Sprintf(`
ZEUGNIS

Schüler/in: %s
Klasse: %s
Schuljahr: Halbjahr %d
Typ: %s

Noten:
%v

Fehlzeiten: %d Tage (davon %d unentschuldigt)

Bemerkungen:
%s

Status: %s
`, cert.StudentName, cert.ClassName, cert.Semester, cert.CertificateType, cert.GradesJSON, cert.AbsenceDays, cert.AbsenceDaysUnexcused, cert.Remarks, cert.Status)

	return []byte(content), nil
}

// DeleteCertificate deletes a certificate (only if draft)
func (s *CertificateService) DeleteCertificate(ctx context.Context, certificateID string) error {
	_, err := s.db.Exec(ctx, `DELETE FROM certificates WHERE id = $1 AND status = 'draft'`, certificateID)
	return err
}

// BulkGenerateCertificates generates certificates for all students in a class
func (s *CertificateService) BulkGenerateCertificates(ctx context.Context, classID, schoolYearID string, semester int, certificateType models.CertificateType, templateName string) ([]models.Certificate, error) {
	// Get all students in the class
	rows, err := s.db.Query(ctx, `SELECT id FROM students WHERE class_id = $1`, classID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var studentIDs []string
	for rows.Next() {
		var id string
		if err := rows.Scan(&id); err != nil {
			return nil, err
		}
		studentIDs = append(studentIDs, id)
	}

	// Generate certificate for each student
	var certificates []models.Certificate
	for _, studentID := range studentIDs {
		cert, err := s.GenerateCertificate(ctx, &models.GenerateCertificateRequest{
			StudentID:       studentID,
			SchoolYearID:    schoolYearID,
			Semester:        semester,
			CertificateType: certificateType,
			TemplateName:    templateName,
		})
		if err != nil {
			// Log error but continue with other students
			continue
		}
		certificates = append(certificates, *cert)
	}

	return certificates, nil
}
