from django.shortcuts import render
from django.http import HttpResponse
from django.db import IntegrityError
import random
import csv
from django.db.models import Count
from django.db.models import Q
from django.db import connections

from .models import Venue
from semester_block.models import Semester_block
from class_session.models import ClassSession

from django_seed import Seed
from faculty.models import Faculty
from programme.models import Programme
from level.models import Level
from teacher.models import Teacher
from module.models import Module
from level_module.models import LevelModule
from teacher_module.models import TeacherModule
from special_venue_module.models import SpecialVenueModule

weekdays_tuple = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
periods_tuple = (1,2,3,4)

# Create your views here.
def doesSeeding(request):
    seeder = Seed.seeder()

    seeder.add_entity(Faculty, 5)
    seeder.add_entity(Semester_block, 1)
    seeder.add_entity(Programme, 10)
    seeder.add_entity(Level, 80)
    seeder.add_entity(Teacher, 30)
    seeder.add_entity(Venue, 10)
    seeder.add_entity(Module, 50)
    seeder.add_entity(Programme, 10)
    seeder.add_entity(LevelModule, 50)
    seeder.add_entity(TeacherModule, 50)

    inserted_pks = seeder.execute()
    return HttpResponse('done')


def handleMassModules(request,semester_block_id):

    # Get the teacher-module combinations with a count greater than 1
    teacher_modules = TeacherModule.objects.values('module', 'teacher'). \
        annotate(count=Count('teacher')). \
        filter(count__gt=1)

    # Get the list of module and teacher IDs
    module_ids = [tm['module'] for tm in teacher_modules]
    teacher_ids = [tm['teacher'] for tm in teacher_modules]

    for teacher_module in teacher_modules:
        module_id = teacher_module['module']
        teacher_id = teacher_module['teacher']
        print(teacher_module)

        #first check if is special venue module
        special_venue_module = SpecialVenueModule.objects.filter(module=module_id).first()
        if special_venue_module != None:
            #go and take the class session which have the same venue
            #and make it to clash
            print('------------------------------------')
            print(special_venue_module)
            print('------------------------------------')

            first_module_level = LevelModule.objects.filter(module=module_id).first()

            class_session_for_special = ClassSession.objects.filter(venue=special_venue_module.venue,
                                                                    teacher__isnull=True).exclude(
                level__id=first_module_level.level_id).first()
            print(class_session_for_special)

            if class_session_for_special == None:
                continue

            module_levels = LevelModule.objects.filter(module=module_id).values()
            print('----------------o-------------------')
            print('module_id'+str(module_id))
            print(module_levels)
            print('----------------o--------------------')
            for module_level in module_levels:
                lm1 = LevelModule(**module_level)

                new_class_session = ClassSession(
                    session_day = class_session_for_special.session_day,
                    period = class_session_for_special.period,
                    duration = class_session_for_special.duration,
                    venue = class_session_for_special.venue,
                    teacher = Teacher.objects.get(pk=teacher_id),
                    module = Module.objects.get(pk=module_id),
                    level = lm1.level,
                    semester_block_id= class_session_for_special.semester_block_id
                )
                try:
                    new_class_session.save()
                    print(new_class_session)
                    print('==============================special-saved=============================')

                    if class_session_for_special.id != None:
                        class_session_for_special.delete()
                except Exception as e:
                    print('expetion '+str(e))
        else:
            first_module_level = LevelModule.objects.filter(module=module_id).last()
            print(module_id)
            print(first_module_level)
            print("mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm")
            if first_module_level == None:
                continue

            class_session = ClassSession.objects.filter(teacher__isnull=True).exclude(
                level__id=first_module_level.level_id).last()

            if class_session == None:
                continue

            module_levels = LevelModule.objects.filter(module=module_id).values()
            for module_level in module_levels:
                lm1 = LevelModule(**module_level)

                new_class_session = ClassSession(
                    session_day=class_session.session_day,
                    period=class_session.period,
                    duration=class_session.duration,
                    venue=class_session.venue,
                    teacher=Teacher.objects.get(pk=teacher_id),
                    module=Module.objects.get(pk=module_id),
                    level=lm1.level,
                    semester_block_id=class_session.semester_block_id
                )

                try:
                    new_class_session.save()
                    print(new_class_session)
                    print('==============================saved=============================')

                    if class_session.id != None:
                        class_session.delete()
                except Exception as e:
                    print('expetion '+str(e))


        print('================================================================================')

    return HttpResponse(".............................................")

def importClassSessions(request,semester_block_id):
    # Open the CSV file
    with open('C:/Users/PC/Documents/django/venv/msuas_timetable/venue/module_teacher_prior.csv', 'r') as csv_file:
        # Create a CSV reader object
        csv_reader = csv.reader(csv_file)
        print( next(csv_reader))

        # Iterate over the rows in the CSV file
        for row in csv_reader:
            if row[0] == 'code':
                continue

            module_code = row[0]
            ec_no = row[2]
            venue_code = row[3]
            session_day = row[4]
            period = row[5]
            duration = row[6]
            level_code = row[7]
            semester_block_id = row[8]

            module = Module.objects.filter(code=module_code).first()
            teacher = Teacher.objects.filter(ec_number=ec_no).first()
            venue = Venue.objects.filter(code=venue_code).first()
            level = Level.objects.filter(code=level_code).first()
            semester_block = Semester_block.objects.filter(pk=semester_block_id).first()

            class_session = ClassSession.objects.filter(session_day=session_day,venue=venue,period=period,duration=duration,semester_block_id=semester_block_id).first()

            if class_session == None:
                class_session = ClassSession(
                    session_day=session_day,
                    period=period,
                    duration=duration,
                    venue=venue,
                    module=module,
                    teacher=teacher,
                    level=level,
                    semester_block=semester_block
                )
            print('-----------------------------------=========================================')
            print(module)
            print(teacher)
            print(venue)
            print(level)
            print(semester_block)
            print(class_session)

            print('-----------------------------------=========================================')

            class_session.module = module
            class_session.level = level
            class_session.teacher = teacher
            try:
                class_session.save()
            except Exception as e:
                print(f"An error occurredcccccc: {e}")

            # Process the row data as needed
            #print(row)


    return HttpResponse(".............................................")


def importTeachers(request):
    # Open the CSV file
    with open('C:/Users/PC/Documents/django/venv/msuas_timetable/venue/employees1.csv', 'r') as csv_file:
        # Create a CSV reader object
        csv_reader = csv.reader(csv_file)
        print( next(csv_reader))

        # Iterate over the rows in the CSV file
        for row in csv_reader:
            if row[0] == 'nationalid':
                continue

            # Create a new Teacher object and save it
            teacher = Teacher(
                national_id=row[0],
                title=row[1],
                surname=row[2],
                name=row[3],
                ec_number=row[4],
                qualification=row[5]
            )
            try:
                teacher.save()
            except Exception as e:
                print(f"An error occurredcccccc: {e}")
                print(f"Ec no: {row[4]}")

            # Process the row data as needed
            #print(row)


    return HttpResponse(".............................................")

def importModules(request):
    # Open the CSV file
    with open('C:/Users/PC/Documents/django/venv/msuas_timetable/venue/modules.csv', 'r') as csv_file:
        # Create a CSV reader object
        csv_reader = csv.reader(csv_file)
        print(next(csv_reader))

        # Iterate over the rows in the CSV file
        for row in csv_reader:
            if row[2] == 'name':
                continue

            module = Module(
                id=row[0],
                code=row[1],
                name=row[2]
            )
            try:
                module.save()
            except Exception as e:
                print(f"An error occurredcccccc: {e}")
                print(f"code : {row[1]}")

    return HttpResponse(".............................................")

def importSpecialVenueModules(request):
    # Open the CSV file
    with open('C:/Users/PC/Documents/django/venv/msuas_timetable/venue/special_module_venue.csv', 'r') as csv_file:
        # Create a CSV reader object
        csv_reader = csv.reader(csv_file)
        print(next(csv_reader))

        # Iterate over the rows in the CSV file
        for row in csv_reader:
            if row[2] == 'venue':
                continue


            try:
                specialvenuemodule = SpecialVenueModule(
                    module=Module.objects.get(code=row[0]),
                    venue=Venue.objects.get(code=row[2])
                )
                specialvenuemodule.save()
            except Exception as e:
                print(f"An error occurredcccccc: {e}")
                print(f"code : {row[1]}")

    return HttpResponse(".............................................")

def importFaculties(request):
    # Open the CSV file
    with open('C:/Users/PC/Documents/django/venv/msuas_timetable/venue/faculties.csv', 'r') as csv_file:
        # Create a CSV reader object
        csv_reader = csv.reader(csv_file)
        print(next(csv_reader))

        # Iterate over the rows in the CSV file
        for row in csv_reader:
            if row[1] == 'name':
                continue

            faculty = Faculty(
                id=row[0],
                name=row[1]
            )
            try:
                faculty.save()
            except Exception as e:
                print(f"An error occurredcccccc: {e}")
                print(f"name : {row[1]}")

    return HttpResponse(".............................................")

def importProgrammes(request):
    # Open the CSV file
    with open('C:/Users/PC/Documents/django/venv/msuas_timetable/venue/programmes.csv', 'r') as csv_file:
        # Create a CSV reader object
        csv_reader = csv.reader(csv_file)
        print(next(csv_reader))

        # Iterate over the rows in the CSV file
        for row in csv_reader:
            if row[2] == 'name':
                continue

            #faculty engineering have 5 years and have an id of 4
            programme = Programme(
                id=row[0],
                faculty=Faculty.objects.get(pk=row[1]),
                name=row[3],
                code=row[2],
                display_name=row[4],
                number_of_years= 5 if row[1] == '4' else 4
            )
            try:
                programme.save()
            except Exception as e:
                print(f"An error occurredcccccc: {e}")
                print(f"name : {row[2]}")

    return HttpResponse(".............................................")

def getEcNumbersFromNames(request):
    with open('C:/Users/PC/Documents/django/venv/msuas_timetable/venue/module_teacher0.csv', 'r') as csv_file:
        # Create a CSV reader object
        csv_reader = csv.reader(csv_file)

        # Read the header row
        header = next(csv_reader)

        print(next(csv_reader))

        # Open the output CSV file
        with open('output.csv', 'w', newline='') as output_file:
            # Create a CSV writer object
            writer = csv.writer(output_file)

            # Write the header row to the output file
            writer.writerow(header)

            # Iterate over the rows in the CSV file
            for row in csv_reader:
                if row[0] == 'code':
                    continue

                surname = row[1]
                parts = surname.split()
                last_part = parts[-1]
                teacher = Teacher.objects.filter(surname__icontains=last_part.lower()).first()
                print(teacher)

                if teacher:
                    ec_no = teacher.ec_number
                    row.append(ec_no)
                else:
                    teacher = Teacher(
                        national_id='11-111111-A-11',
                        title='M',
                        surname=last_part,
                        name=last_part,
                        ec_number=random.randint(5000,10000),
                        qualification="Masters"
                    )
                    teacher.save()

                # Write the updated row to the output file
                writer.writerow(row)

    return HttpResponse(".............................................")

def importModuleTeachers(request):
    with (open('C:/Users/PC/Documents/django/venv/msuas_timetable/venue/module_teacher.csv', 'r') as csv_file):
        # Create a CSV reader object
        csv_reader = csv.reader(csv_file)
        print(next(csv_reader))

        # Iterate over the rows in the CSV file
        for row in csv_reader:
            if row[0] == 'code':
                continue

            module_code = row[0].strip()
            module_code = "".join(module_code.split())
            ec_no = row[2]

            try:
                teachermodule = TeacherModule(
                    module=Module.objects.get(code=module_code),
                    teacher=Teacher.objects.get(ec_number=ec_no),
                )
                teachermodule.save()
            except Exception as e:
                print("=============g===================")
                print("module code: "+module_code)
                print(e)
                print("=============g===================")

            print(teachermodule)

        return HttpResponse(".............................................")

def importLevelmodules(request):
    # Open the CSV file
    with open('C:/Users/PC/Documents/django/venv/msuas_timetable/venue/levelmodules.csv', 'r') as csv_file:
        # Create a CSV reader object
        csv_reader = csv.reader(csv_file)
        print(next(csv_reader))

        # Iterate over the rows in the CSV file
        for row in csv_reader:
            if row[1] == 'academicyear':
                continue

            print('pr id'+row[0])
            print('academic_year' + row[1])
            print('academic_semester' + row[2])
            print('code' + row[4])

            level_a = Level.objects.get(programme_id=row[0],academic_year=row[1],academic_semester=row[2])

            levelmodule = LevelModule(
                module=Module.objects.get(pk=row[3]),
                level=level_a,
            )

            try:
                levelmodule.save()
            except Exception as e:
                print(f"An error occurredcccccc: {e}")
                print(f"code : {row[4]}")

    return HttpResponse(".............................................")

def populateProgrammeLevel(request):
    programmes = Programme.objects.all().values()
    for programme in programmes:
        programme = Programme(**programme)
        print(programme.name)

        for i in range(1, programme.number_of_years+1):
            print(i)
            level1 = Level(
                programme=programme,
                code=programme.code+'-'+str(i)+'.1',
                name=str(i)+'.1',
                academic_year=i,
                academic_semester=1
            )

            level2 = Level(
                programme=programme,
                code=programme.code+'-'+str(i)+'.2',
                name=str(i) + '.2',
                academic_year=i,
                academic_semester=2
            )
            try:
                level1.save()
                level2.save()
            except Exception as e:
                print(f"An error occurredcccccc: {e}")

    return HttpResponse("..................................")

def correctTheSeeds(request):
    programmes = Programme.objects.all().values()
    for programme in programmes:
        programme = Programme(**programme)
        rand = " "+str(random.randint(1,10))
        name = programme.name+rand
        display_name = programme.display_name+rand
        programme.name = name.split()[0] if name.split()[0] != "Bachelor" else name
        programme.display_name = display_name.split()[0] if display_name.split()[0] != "Bachelor" else display_name
        try:
            programme.save()
        except IntegrityError:
            pass

    facultys = Faculty.objects.all().values()
    for faculty1 in facultys:
        faculty = Faculty(**faculty1)
        rand = " " + str(random.randint(1, 10))
        name = faculty.name.split()[0] + rand
        faculty.name = name
        try:
            faculty.save()
        except IntegrityError:
            pass

    venues = Venue.objects.all().values()
    for venue1 in venues:
        venue = Venue(**venue1)
        rand = " " + str(random.randint(1, 10))
        name = venue.name.split()[0]
        code = venue.code.split()[0]
        venue.name = name + rand
        venue.code = code + rand
        try:
            venue.save()
        except IntegrityError:
            pass

    modules = Module.objects.all().values()
    for module1 in modules:
        module = Module(**module1)
        if module.id > 0:
            name = module.name
            code = module.code
            rand = " " + str(random.randint(1, 10))
            module.name = name.split()[0]+" "+name.split()[0]+" "+name.split()[0]+rand
            module.code = code.split()[0]+" "+code.split()[0]+" "+code.split()[0]+rand
            try:
                module.save()
            except IntegrityError:
                pass

    teachers = Teacher.objects.all().values()
    for teacher1 in teachers:
        teacher = Teacher(**teacher1)
        name = teacher.name
        surname = teacher.surname
        ec_number = teacher.ec_number
        rand = " " + str(random.randint(1, 10))
        teacher.name = name.split()[0]+" "+name.split()[0]+str(rand)
        teacher.surname = surname.split()[0]+" "+surname.split()[0]+str(rand)
        teacher.ec_number = ec_number.split()[0]+" "+ec_number.split()[0]+str(rand)

        try:
            print(teacher.name)
            teacher.save()
        except IntegrityError:
            pass

    return HttpResponse("seed correction is done")

def GivePeriodsToAllVenues(request,semester_block_id = 1):
    #generate class sessions
    #this will take monday to friday and occupy each venue, each period
    #for the same semester block
    #wednesdays afternoons are occupied by sports

    venues = Venue.objects.all().values()
    teacher_modules = TeacherModule.objects.all().values()
    level_modules = LevelModule.objects.all().values()
    message = 'stage 1 venue loop thru'
    for venue in venues:
        v1 = Venue(**venue)
        #now we have access to venue properties
        message = 'stage 2 weekdays loop thru'
        for weekday in weekdays_tuple:
            #now weekday as per venue
            message = 'stage 3 periods loop thru'
            for period in periods_tuple:

                # if weekday == 'Wednesday' and period > 3:
                #     continue

                if v1.code == 'CL':
                    continue

                #now period of a weekday of each venue
                smb = Semester_block.objects.filter(id=semester_block_id).values()
                smb1 = Semester_block(**smb.first())
                message = 'stage 4 teacher module loop thru'

                obj = ClassSession(session_day=weekday,period=period,duration=2,venue=v1,semester_block=smb1)

                try:
                    obj.save()
                except IntegrityError:
                    pass
                message = 'stage 5 venue allocation completed'


    return HttpResponse(message)

def GiveTeacherModuleForSpecialVenues(request,semester_block_id=1):
    #first deal with special venues and modules and assign them to their respective

    special_venue_modules = SpecialVenueModule.objects.all().values()
    for special_venue_module in special_venue_modules:
        svm1 = SpecialVenueModule(**special_venue_module)

        venue_id = svm1.venue_id
        module_id = svm1.module_id



        #the module if not added in teachermodule it will give an error
        #we want all teacher modules for this module
        print('module_id =============='+str(module_id))
        #teacher_modules = TeacherModule.objects.filter(module_id=module_id).values()

        # Step 1: Get the list of teacher_id values that appear more than 3 times in ClassSession
        over_three_teachers = ClassSession.objects.values('teacher_id'). \
            annotate(count=Count('teacher_id')). \
            filter(count__gt=7). \
            values_list('teacher_id', flat=True)

        #Step 2: Filter the TeacherModule queryset to exclude the teachers from the list
        teacher_modules = TeacherModule.objects.exclude(teacher_id__in=over_three_teachers). \
            filter(module_id=module_id). \
            values()

        if teacher_modules.first() == None:
            continue
        tm1 = TeacherModule(**teacher_modules.first())
        for teacher_module in teacher_modules:
            tm1 = TeacherModule(**teacher_module)
            print(tm1.teacher.id)

            class_sessions = ClassSession.objects.filter(venue=venue_id, teacher_id__isnull=True).order_by(
                'period').first()
            if class_sessions == None:
                continue
            fcs1 = class_sessions

            possible_prior_class_session_allocations = ClassSession.objects.filter(teacher=tm1.teacher.id,module=module_id)
            if possible_prior_class_session_allocations:
                continue
            print('((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((dddddddddddddd))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))')

            print('module +'+str(tm1.module.id))
            fcs1.module = Module.objects.get(pk=tm1.module.id)
            print('dddddddddddddd')
            print(fcs1.module)
            fcs1.teacher = Teacher.objects.get(pk=tm1.teacher.id)

            #a module can belong to different progs and diff levels
            level_modules = LevelModule.objects.filter(module=module_id).values()
            for level_module in level_modules:
                lm1 = LevelModule(**level_module)
                cs2 = ClassSession.objects.filter(level=lm1.id,module=module_id).values()
                if cs2.first() == None:
                    fcs1.level = Level.objects.get(pk=lm1.level.id)
                    fcs2s = ClassSession.objects.filter(venue=venue_id, teacher_id__isnull=True).order_by(
                        'period').values()
                    #where teacher does not clash
                    #where module does not clash
                    #where level does not clash
                    for fcs2 in fcs2s:
                        final_fcs = ClassSession(**fcs2)
                        check_duplicates = ClassSession.objects.filter(module=module_id, level=lm1.level.id,
                                                                       teacher=tm1.teacher.id,
                                                                       teacher_id__isnull=False).values()
                        if len(check_duplicates):
                            continue

                        try:
                            fcs1.save()
                            #final_fcs.save()
                            print('--------------------------------saved--------------------------------')
                            break
                            #go and take the class session for this venue and occupy it
                        except Exception as e:
                            print(f"An error occurredcccccc: {e}")


    return HttpResponse("done")

def GiveTeacherModuleForAllVenues(request,semester_block_id=1):
    # Step 1: Get the list of teacher_id values that appear more than 3 times in ClassSession
    over_three_teachers = ClassSession.objects.values('teacher_id'). \
        annotate(count=Count('teacher_id')). \
        filter(count__gt=7). \
        values_list('teacher_id', flat=True)

    # Step 2: Filter the TeacherModule queryset to exclude the teachers from the list
    teacher_modules = TeacherModule.objects.exclude(teacher_id__in=over_three_teachers).values()

    for teacher_module in teacher_modules:
        tm1 = TeacherModule(**teacher_module)
        print(tm1.teacher.id)
        teacher_id = tm1.teacher.id
        print('((((((((((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))))))')

        print('module +' + str(tm1.module.id))
        module_id = tm1.module.id

        # possible_prior_class_session_allocations = ClassSession.objects.filter(teacher=tm1.teacher.id, module=module_id)
        # if possible_prior_class_session_allocations:
        #     continue

        # a module can belong to different progs and diff levels
        level_modules = LevelModule.objects.filter(module=module_id).values()
        for level_module in level_modules:
            lm1 = LevelModule(**level_module)
            level_id = lm1.level.id

            class_sessions = ClassSession.objects.filter(teacher_id__isnull=True).order_by('session_day').values()
            for class_session in class_sessions:

                fcs1 = ClassSession(**class_session)

                fcs1.module = Module.objects.get(pk=module_id)
                fcs1.level = Level.objects.get(pk=level_id)
                fcs1.teacher = Teacher.objects.get(pk=teacher_id)

                check_duplicates = ClassSession.objects.filter(module=module_id,level=level_id,teacher=teacher_id,teacher_id__isnull=False).values()
                if len(check_duplicates):
                    continue

                try:
                    fcs1.save()
                    print('--------------------------------saved--------------------------------')
                    break
                    # go and take the class session for this venue and occupy it
                except Exception as e:
                    print(f"An error occurredcccccc: {e}")

    return HttpResponse("done")


