package seed

import (
	"context"
	"fmt"
	"log"
	"math/rand"
	"time"

	"github.com/google/uuid"
	"github.com/jackc/pgx/v5/pgxpool"
)

// Seeder generates demo data for the school service
type Seeder struct {
	pool      *pgxpool.Pool
	teacherID uuid.UUID
	rng       *rand.Rand
}

// NewSeeder creates a new seeder instance
func NewSeeder(pool *pgxpool.Pool, teacherID uuid.UUID) *Seeder {
	return &Seeder{
		pool:      pool,
		teacherID: teacherID,
		rng:       rand.New(rand.NewSource(time.Now().UnixNano())),
	}
}

// German first names for realistic demo data
var firstNames = []string{
	"Max", "Paul", "Leon", "Felix", "Jonas", "Lukas", "Tim", "Ben", "Finn", "Elias",
	"Emma", "Mia", "Hannah", "Sophia", "Lena", "Anna", "Marie", "Leonie", "Lara", "Laura",
	"Noah", "Luis", "David", "Moritz", "Jan", "Niklas", "Tom", "Simon", "Erik", "Jannik",
	"Lea", "Julia", "Lisa", "Sarah", "Clara", "Amelie", "Emily", "Maja", "Zoe", "Lina",
	"Alexander", "Maximilian", "Sebastian", "Philipp", "Julian", "Fabian", "Tobias", "Christian",
	"Katharina", "Christina", "Johanna", "Franziska", "Antonia", "Victoria", "Helena", "Charlotte",
}

// German last names for realistic demo data
var lastNames = []string{
	"Mueller", "Schmidt", "Schneider", "Fischer", "Weber", "Meyer", "Wagner", "Becker",
	"Schulz", "Hoffmann", "Koch", "Bauer", "Richter", "Klein", "Wolf", "Schroeder",
	"Neumann", "Schwarz", "Zimmermann", "Braun", "Krueger", "Hofmann", "Hartmann", "Lange",
	"Schmitt", "Werner", "Schmitz", "Krause", "Meier", "Lehmann", "Schmid", "Schulze",
	"Maier", "Koehler", "Herrmann", "Koenig", "Walter", "Mayer", "Huber", "Kaiser",
	"Peters", "Lang", "Scholz", "Moeller", "Gross", "Jung", "Friedrich", "Keller",
}

// Subjects with exam data
type SubjectConfig struct {
	Name          string
	ShortName     string
	IsMain        bool
	ExamsPerYear  int
	WrittenWeight int
}

var subjects = []SubjectConfig{
	{"Deutsch", "De", true, 4, 60},
	{"Mathematik", "Ma", true, 4, 60},
	{"Englisch", "En", true, 4, 60},
	{"Biologie", "Bio", false, 3, 50},
	{"Geschichte", "Ge", false, 2, 50},
	{"Physik", "Ph", false, 3, 50},
	{"Chemie", "Ch", false, 2, 50},
	{"Sport", "Sp", false, 0, 30},
	{"Kunst", "Ku", false, 1, 40},
	{"Musik", "Mu", false, 1, 40},
}

// SeedAll generates all demo data
func (s *Seeder) SeedAll(ctx context.Context) error {
	log.Println("Starting seed data generation...")

	// 1. Create school years
	schoolYears, err := s.seedSchoolYears(ctx)
	if err != nil {
		return fmt.Errorf("seeding school years: %w", err)
	}
	log.Printf("Created %d school years", len(schoolYears))

	// 2. Create subjects
	subjectIDs, err := s.seedSubjects(ctx)
	if err != nil {
		return fmt.Errorf("seeding subjects: %w", err)
	}
	log.Printf("Created %d subjects", len(subjectIDs))

	// 3. Create classes with students
	for _, sy := range schoolYears {
		classes, err := s.seedClassesForYear(ctx, sy)
		if err != nil {
			return fmt.Errorf("seeding classes for year %s: %w", sy.Name, err)
		}

		for _, class := range classes {
			// Create students
			students, err := s.seedStudentsForClass(ctx, class.ID)
			if err != nil {
				return fmt.Errorf("seeding students for class %s: %w", class.Name, err)
			}
			log.Printf("Created %d students for class %s", len(students), class.Name)

			// Create exams and results
			for _, subj := range subjects {
				subjectID := subjectIDs[subj.Name]
				err := s.seedExamsAndResults(ctx, class.ID, subjectID, students, sy.ID, subj)
				if err != nil {
					return fmt.Errorf("seeding exams for class %s, subject %s: %w", class.Name, subj.Name, err)
				}
			}

			// Create attendance records
			err = s.seedAttendance(ctx, students, sy)
			if err != nil {
				return fmt.Errorf("seeding attendance for class %s: %w", class.Name, err)
			}
		}
	}

	log.Println("Seed data generation completed successfully!")
	return nil
}

// SchoolYearResult holds created school year info
type SchoolYearResult struct {
	ID        uuid.UUID
	Name      string
	StartDate time.Time
	EndDate   time.Time
	IsCurrent bool
}

func (s *Seeder) seedSchoolYears(ctx context.Context) ([]SchoolYearResult, error) {
	years := []struct {
		name      string
		startYear int
		isCurrent bool
	}{
		{"2022/23", 2022, false},
		{"2023/24", 2023, false},
		{"2024/25", 2024, true},
	}

	var results []SchoolYearResult
	for _, y := range years {
		id := uuid.New()
		startDate := time.Date(y.startYear, time.August, 1, 0, 0, 0, 0, time.UTC)
		endDate := time.Date(y.startYear+1, time.July, 31, 0, 0, 0, 0, time.UTC)

		_, err := s.pool.Exec(ctx, `
			INSERT INTO school_years (id, name, start_date, end_date, is_current, teacher_id)
			VALUES ($1, $2, $3, $4, $5, $6)
			ON CONFLICT DO NOTHING
		`, id, y.name, startDate, endDate, y.isCurrent, s.teacherID)

		if err != nil {
			return nil, err
		}

		results = append(results, SchoolYearResult{
			ID:        id,
			Name:      y.name,
			StartDate: startDate,
			EndDate:   endDate,
			IsCurrent: y.isCurrent,
		})
	}

	return results, nil
}

func (s *Seeder) seedSubjects(ctx context.Context) (map[string]uuid.UUID, error) {
	subjectIDs := make(map[string]uuid.UUID)

	for _, subj := range subjects {
		id := uuid.New()
		_, err := s.pool.Exec(ctx, `
			INSERT INTO subjects (id, teacher_id, name, short_name, is_main_subject)
			VALUES ($1, $2, $3, $4, $5)
			ON CONFLICT (teacher_id, name) DO UPDATE SET id = subjects.id
			RETURNING id
		`, id, s.teacherID, subj.Name, subj.ShortName, subj.IsMain)

		if err != nil {
			return nil, err
		}
		subjectIDs[subj.Name] = id
	}

	return subjectIDs, nil
}

// ClassResult holds created class info
type ClassResult struct {
	ID         uuid.UUID
	Name       string
	GradeLevel int
}

func (s *Seeder) seedClassesForYear(ctx context.Context, sy SchoolYearResult) ([]ClassResult, error) {
	// Classes: 5a, 5b, 6a, 6b, 7a, 7b
	classConfigs := []struct {
		name       string
		gradeLevel int
	}{
		{"5a", 5}, {"5b", 5},
		{"6a", 6}, {"6b", 6},
		{"7a", 7}, {"7b", 7},
	}

	var results []ClassResult
	for _, c := range classConfigs {
		id := uuid.New()
		_, err := s.pool.Exec(ctx, `
			INSERT INTO classes (id, teacher_id, school_year_id, name, grade_level, school_type, federal_state)
			VALUES ($1, $2, $3, $4, $5, $6, $7)
			ON CONFLICT (teacher_id, school_year_id, name) DO UPDATE SET id = classes.id
		`, id, s.teacherID, sy.ID, c.name, c.gradeLevel, "gymnasium", "niedersachsen")

		if err != nil {
			return nil, err
		}

		results = append(results, ClassResult{
			ID:         id,
			Name:       c.name,
			GradeLevel: c.gradeLevel,
		})
	}

	return results, nil
}
