"""
Management command: seed_dev_data
Populates the development database with realistic sample data.
Safe to run multiple times — uses get_or_create throughout.

Usage:
    python manage.py seed_dev_data
"""
import datetime
import random
import shutil
from decimal import Decimal
from pathlib import Path

from django.conf import settings
from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand
from django.utils import timezone

from admissions.models import Enrollment, Program
from certificates.models import Certificate
from courses.models import Course
from grades.models import Result
from payments.models import Donation, Payment
from website.models import GalleryImage

User = get_user_model()

ACADEMIC_YEAR = '2024/2025'
RECORDER_USERNAME = 'admin'


# ── helpers ────────────────────────────────────────────────────────────────

def _grade_and_marks(level):
    """Return (grade, marks) for a given performance level A/B/C/D/F."""
    ranges = {
        'A': (82, 97),
        'B': (66, 79),
        'C': (51, 63),
        'D': (41, 49),
        'F': (20, 38),
    }
    lo, hi = ranges[level]
    marks = random.randint(lo, hi)
    return level, marks


def _add_results(enrollment, courses, term, grade_map, recorder):
    """Create theory + practical + exam results for a list of courses."""
    for course, levels in zip(courses, grade_map):
        theory_lvl, practical_lvl, exam_lvl = levels
        for grade_type, lvl in [
            (Result.THEORY, theory_lvl),
            (Result.PRACTICAL, practical_lvl),
            (Result.EXAM, exam_lvl),
        ]:
            grade, marks = _grade_and_marks(lvl)
            Result.objects.get_or_create(
                enrollment=enrollment,
                course=course,
                grade_type=grade_type,
                term=term,
                academic_year=ACADEMIC_YEAR,
                defaults={'grade': grade, 'marks': marks, 'recorded_by': recorder},
            )


class Command(BaseCommand):
    help = 'Seed development database with sample students, results, donations and payments.'

    def handle(self, *args, **options):
        recorder = User.objects.filter(role__in=[User.ADMIN, User.SUPER_ADMIN]).first()

        self._seed_results_existing(recorder)
        self._seed_new_students(recorder)
        self._seed_donations()
        self._seed_gallery()
        self.stdout.write(self.style.SUCCESS('Seed complete.'))

    # ── existing students ────────────────────────────────────────────────────

    def _seed_results_existing(self, recorder):
        # Patricia Namutebi — Tailoring (Enrollment 1)
        try:
            patricia_enroll = Enrollment.objects.get(pk=1)
            tailoring_y1 = list(Course.objects.filter(
                program=patricia_enroll.program, year=1
            ).order_by('name'))

            if tailoring_y1:
                # Term 1 — strong performer
                _add_results(patricia_enroll, tailoring_y1, 'term_1', [
                    ('A', 'A', 'B'),
                    ('B', 'A', 'B'),
                    ('A', 'B', 'A'),
                    ('B', 'B', 'B'),
                ][:len(tailoring_y1)], recorder)

                # Term 2 — slightly varied
                _add_results(patricia_enroll, tailoring_y1, 'term_2', [
                    ('A', 'A', 'A'),
                    ('B', 'A', 'B'),
                    ('C', 'B', 'B'),
                    ('A', 'A', 'B'),
                ][:len(tailoring_y1)], recorder)

                # Term 3 — year-end
                _add_results(patricia_enroll, tailoring_y1, 'term_3', [
                    ('A', 'A', 'A'),
                    ('A', 'B', 'A'),
                    ('B', 'A', 'B'),
                    ('A', 'A', 'A'),
                ][:len(tailoring_y1)], recorder)

            self.stdout.write('  Patricia: results seeded.')
        except Enrollment.DoesNotExist:
            self.stdout.write(self.style.WARNING('  Enrollment 1 not found, skipping Patricia.'))

        # Samuel Wasswa — Motor Vehicle Mechanics (Enrollment 2)
        try:
            samuel_enroll = Enrollment.objects.get(pk=2)
            mvm_y1 = list(Course.objects.filter(
                program=samuel_enroll.program, year=1
            ).order_by('name'))

            if mvm_y1:
                # Term 1 — good
                _add_results(samuel_enroll, mvm_y1, 'term_1', [
                    ('B', 'A', 'B'),
                    ('C', 'B', 'C'),
                    ('B', 'B', 'B'),
                    ('A', 'A', 'B'),
                ][:len(mvm_y1)], recorder)

                # Term 2 — improving
                _add_results(samuel_enroll, mvm_y1, 'term_2', [
                    ('A', 'B', 'A'),
                    ('B', 'B', 'B'),
                    ('B', 'A', 'B'),
                    ('C', 'B', 'B'),
                ][:len(mvm_y1)], recorder)

            self.stdout.write('  Samuel: results seeded.')
        except Enrollment.DoesNotExist:
            self.stdout.write(self.style.WARNING('  Enrollment 2 not found, skipping Samuel.'))

    # ── new students ─────────────────────────────────────────────────────────

    def _seed_new_students(self, recorder):
        new_students = [
            {
                'username': 'david.ochieng@gmail.com',
                'first_name': 'David',
                'last_name': 'Ochieng',
                'program_pk': 1,   # Electrical Installation
                'student_number': 'MLS/EL/2024/003',
                'grades_t1': ['B', 'A', 'B', 'C'],
                'grades_t2': ['A', 'B', 'A', 'B'],
            },
            {
                'username': 'grace.apio@gmail.com',
                'first_name': 'Grace',
                'last_name': 'Apio',
                'program_pk': 8,   # ICT / Computer Studies
                'student_number': 'MLS/ICT/2024/004',
                'grades_t1': ['A', 'A', 'B', 'A'],
                'grades_t2': ['A', 'A', 'A', 'B'],
            },
            {
                'username': 'moses.kiggundu@gmail.com',
                'first_name': 'Moses',
                'last_name': 'Kiggundu',
                'program_pk': 4,   # Welding & Metal Fabrication
                'student_number': 'MLS/WL/2024/005',
                'grades_t1': ['C', 'B', 'C', 'B'],
                'grades_t2': ['B', 'B', 'C', 'A'],
            },
            {
                'username': 'esther.namukasa@gmail.com',
                'first_name': 'Esther',
                'last_name': 'Namukasa',
                'program_pk': 2,   # Carpentry & Joinery
                'student_number': 'MLS/CJ/2024/006',
                'grades_t1': ['B', 'C', 'B', 'B'],
                'grades_t2': ['A', 'B', 'B', 'A'],
            },
        ]

        for s in new_students:
            try:
                program = Program.objects.get(pk=s['program_pk'])
            except Program.DoesNotExist:
                self.stdout.write(self.style.WARNING(f"  Program {s['program_pk']} not found, skipping {s['first_name']}."))
                continue

            user, created = User.objects.get_or_create(
                username=s['username'],
                defaults={
                    'first_name': s['first_name'],
                    'last_name': s['last_name'],
                    'email': s['username'],
                    'role': User.STUDENT,
                },
            )
            if created:
                user.set_password('student123')
                user.save()

            enrollment, _ = Enrollment.objects.get_or_create(
                student=user,
                defaults={
                    'program': program,
                    'student_number': s['student_number'],
                    'is_active': True,
                },
            )

            courses_y1 = list(Course.objects.filter(program=program, year=1).order_by('name'))
            if not courses_y1:
                self.stdout.write(self.style.WARNING(f"  No Y1 courses for {program.name}, skipping results."))
                continue

            grade_pairs_t1 = [(g, g, g) for g in s['grades_t1']]
            grade_pairs_t2 = [(g, g, g) for g in s['grades_t2']]

            _add_results(enrollment, courses_y1, 'term_1', grade_pairs_t1[:len(courses_y1)], recorder)
            _add_results(enrollment, courses_y1, 'term_2', grade_pairs_t2[:len(courses_y1)], recorder)

            self.stdout.write(f'  {user.get_full_name()} ({program.name}): seeded.')

    # ── donations ────────────────────────────────────────────────────────────

    def _seed_donations(self):
        sample_donations = [
            {
                'name': 'Robert Kawesi',
                'email': 'r.kawesi@gmail.com',
                'phone': '+256772345678',
                'amount': Decimal('150000'),
                'message': 'Keep up the great work empowering our youth!',
                'flw_tx_ref': 'MLS-DON-SEED001',
                'status': Donation.COMPLETED,
                'flw_transaction_id': 'FLW-SEED-001',
                'completed_at': timezone.now() - datetime.timedelta(days=30),
            },
            {
                'name': 'Sarah Mutesi',
                'email': 'sarah.mutesi@yahoo.com',
                'phone': '+256701234567',
                'amount': Decimal('500000'),
                'message': 'Supporting vocational education in Uganda.',
                'flw_tx_ref': 'MLS-DON-SEED002',
                'status': Donation.COMPLETED,
                'flw_transaction_id': 'FLW-SEED-002',
                'completed_at': timezone.now() - datetime.timedelta(days=15),
            },
            {
                'name': 'James Opolot',
                'email': 'j.opolot@outlook.com',
                'phone': '+256752000111',
                'amount': Decimal('250000'),
                'message': '',
                'flw_tx_ref': 'MLS-DON-SEED003',
                'status': Donation.COMPLETED,
                'flw_transaction_id': 'FLW-SEED-003',
                'completed_at': timezone.now() - datetime.timedelta(days=7),
            },
            {
                'name': 'Anonymous Donor',
                'email': 'anon@example.com',
                'phone': '',
                'amount': Decimal('75000'),
                'message': '',
                'flw_tx_ref': 'MLS-DON-SEED004',
                'status': Donation.PENDING,
                'flw_transaction_id': '',
                'completed_at': None,
            },
        ]

        for d in sample_donations:
            obj, created = Donation.objects.get_or_create(
                flw_tx_ref=d['flw_tx_ref'],
                defaults={k: v for k, v in d.items() if k != 'flw_tx_ref'},
            )
            if created:
                self.stdout.write(f"  Donation from {d['name']}: seeded.")

    # ── gallery ──────────────────────────────────────────────────────────────

    def _seed_gallery(self):
        # Remove old AI-placeholder seed images so only real photos remain
        old_seed_filenames = [
            'gallery/seed_classroom.webp',
            'gallery/seed_community.webp',
            'gallery/seed_vocational.webp',
            'gallery/seed_women_business.webp',
            'gallery/seed_graduates.webp',
        ]
        for fname in old_seed_filenames:
            qs = GalleryImage.objects.filter(image=fname)
            for obj in qs:
                old_file = Path(settings.MEDIA_ROOT) / fname
                if old_file.exists():
                    old_file.unlink()
                obj.delete()
                self.stdout.write(f"  Gallery: removed old placeholder '{fname}'.")

        real_images = [
            {
                'src': 'website/images/photo_1.jpeg',
                'dest': 'gallery/photo_1.jpeg',
                'title': 'Electrical Circuit Theory Lesson',
                'description': 'A trainee presents Z-parameter circuit analysis on the board during an Electrical Installation class.',
                'category': 'training',
                'order': 1,
            },
            {
                'src': 'website/images/photo_2.jpeg',
                'dest': 'gallery/photo_2.jpeg',
                'title': 'Evening Training Session',
                'description': 'A packed evening class showing the dedication of our trainees and instructors.',
                'category': 'training',
                'order': 2,
            },
            {
                'src': 'website/images/photo_3.jpeg',
                'dest': 'gallery/photo_3.jpeg',
                'title': 'Instructor-Led Technical Training',
                'description': 'An instructor guides students through technical content at the blackboard.',
                'category': 'training',
                'order': 3,
            },
            {
                'src': 'website/images/photo_4.jpeg',
                'dest': 'gallery/photo_4.jpeg',
                'title': 'Students at a Training Session',
                'description': 'Trainees engaged with course materials during a busy class at our training centre.',
                'category': 'training',
                'order': 4,
            },
            {
                'src': 'website/images/photo_5.jpeg',
                'dest': 'gallery/photo_5.jpeg',
                'title': 'Full Training Hall in Session',
                'description': 'A wide view of our training hall filled with motivated learners.',
                'category': 'facilities',
                'order': 5,
            },
            {
                'src': 'website/images/photo_6.jpeg',
                'dest': 'gallery/photo_6.jpeg',
                'title': 'Active Learning in Progress',
                'description': 'Students follow along attentively as the instructor explains course content.',
                'category': 'training',
                'order': 6,
            },
            {
                'src': 'website/images/photo_7.jpeg',
                'dest': 'gallery/photo_7.jpeg',
                'title': 'Classroom Study Session',
                'description': 'Trainees working through problems together in a well-lit classroom facility.',
                'category': 'facilities',
                'order': 7,
            },
        ]

        media_gallery = Path(settings.MEDIA_ROOT) / 'gallery'
        media_gallery.mkdir(parents=True, exist_ok=True)

        static_root = Path(settings.BASE_DIR) / 'static'

        for item in real_images:
            if GalleryImage.objects.filter(image=item['dest']).exists():
                continue
            src_path = static_root / item['src']
            dest_path = Path(settings.MEDIA_ROOT) / item['dest']
            if not src_path.exists():
                self.stdout.write(self.style.WARNING(f"  Source not found: {src_path}"))
                continue
            shutil.copy2(src_path, dest_path)
            GalleryImage.objects.create(
                title=item['title'],
                description=item['description'],
                image=item['dest'],
                category=item['category'],
                display_order=item['order'],
                is_published=True,
            )
            self.stdout.write(f"  Gallery: '{item['title']}' seeded.")
