from datetime import datetime, time, timedelta

import djclick as click
import structlog
from django.utils import timezone

from vbv_lernwelt.assignment.models import Assignment, AssignmentCompletion
from vbv_lernwelt.core.admin import User
from vbv_lernwelt.course.consts import (
    COURSE_VERSICHERUNGSVERMITTLERIN_FR_ID,
    COURSE_VERSICHERUNGSVERMITTLERIN_ID,
    COURSE_VERSICHERUNGSVERMITTLERIN_IT_ID,
)
from vbv_lernwelt.course.models import (
    Course,
    CourseCompletion,
    CourseSession,
    CourseSessionUser,
)
from vbv_lernwelt.course_session.models import (
    CourseSessionAssignment,
    CourseSessionAttendanceCourse,
    CourseSessionEdoniqTest,
)
from vbv_lernwelt.course_session_group.models import CourseSessionGroup
from vbv_lernwelt.feedback.models import FeedbackResponse
from vbv_lernwelt.learning_mentor.models import LearningMentor
from vbv_lernwelt.learnpath.models import Circle
from vbv_lernwelt.notify.models import Notification

logger = structlog.get_logger(__name__)
from vbv_lernwelt.importer.services import (
    create_or_update_course_session,
    get_uk_course,
    LP_DATA,
    TRANSLATIONS,
)

IT_VV_TEST_COURSE = "Iterativ VV Testkurs"
IT_UK_TEST_COURSE = "Iterativ üK Testkurs"
IT_UK_TEST_REGION = "Iterativ Region"
TIME_FORMAT = "%d.%m.%Y, %H:%M"
PASSWORD = "myvbv1234"

logger = structlog.get_logger(__name__)


@click.command()
def command():
    create_or_update_uk()
    create_or_update_vv()


def create_or_update_uk(language="de"):
    uk_course = get_uk_course(language)
    uk_circle_keys = [
        "Kickoff",
        "Basis",
        "Fahrzeug",
        "Haushalt Teil 1",
        "Haushalt Teil 2",
    ]

    data = create_uk_data(language)
    create_or_update_course_session(
        uk_course,
        data,
        language,
        circle_keys=uk_circle_keys,
    )
    cs = CourseSession.objects.get(import_id=data["ID"])

    members, trainer, regionenleiter = get_or_create_users_uk()
    delete_cs_data(cs, members + [trainer, regionenleiter])

    add_to_course_session(cs, members)
    add_trainers_to_course_session(cs, [trainer], uk_circle_keys, language)
    create_and_add_to_cs_group(cs.course, IT_UK_TEST_REGION, [cs], regionenleiter)


def create_or_update_vv(language="de"):
    vv_course = get_vv_course(language)

    cs, _created = CourseSession.objects.get_or_create(
        course=vv_course, import_id=IT_VV_TEST_COURSE
    )
    cs.title = IT_VV_TEST_COURSE
    cs.save()

    create_or_update_assignment_course_session(cs)
    members, member_with_mentor, mentor = get_or_create_users_vv()
    delete_cs_data(cs, members + [member_with_mentor, mentor])

    add_to_course_session(cs, members + [member_with_mentor])
    add_mentor_to_course_session(cs, [(mentor, member_with_mentor)])


def delete_cs_data(cs: CourseSession, users: list[User]):
    if cs:
        CourseCompletion.objects.filter(course_session=cs).delete()
        Notification.objects.filter(course_session=cs).delete()
        AssignmentCompletion.objects.filter(course_session=cs).delete()
        CourseSessionAttendanceCourse.objects.filter(course_session=cs).update(
            attendance_user_list=[]
        )
        CourseSessionEdoniqTest.objects.filter(course_session=cs).delete()
        CourseSessionUser.objects.filter(course_session=cs).delete()
        learning_mentor_ids = (
            LearningMentor.objects.filter(participants__course_session=cs)
            .values_list("id", flat=True)
            .distinct()
            | LearningMentor.objects.filter(mentor__in=users)
            .values_list("id", flat=True)
            .distinct()
        )
        # cannot call delete on distinct objects
        LearningMentor.objects.filter(id__in=list(learning_mentor_ids)).delete()
    else:
        logger.info("no_course_session_found", import_id=cs.import_id)

    FeedbackResponse.objects.filter(feedback_user__in=users).delete()


def add_to_course_session(
    course_session: CourseSession,
    members: list[User],
    role=CourseSessionUser.Role.MEMBER,
):
    if course_session:
        for user in members:
            csu, _created = CourseSessionUser.objects.get_or_create(
                course_session_id=course_session.id, user_id=user.id, role=role
            )
            csu.save()


def add_mentor_to_course_session(
    course_session: CourseSession, mentor_mentee_pairs: list[tuple[User, User]]
):
    for mentor, mentee in mentor_mentee_pairs:
        lm = LearningMentor.objects.create(
            course=course_session.course,
            mentor=mentor,
        )
        lm.participants.add(
            CourseSessionUser.objects.get(
                user__id=mentee.id,
                course_session=course_session,
            )
        )


def add_trainers_to_course_session(
    course_session: CourseSession,
    trainers: list[User],
    circle_keys: list[str],
    language,
):
    add_to_course_session(course_session, trainers, CourseSessionUser.Role.EXPERT)
    for user in trainers:
        for circle_key in circle_keys:
            circle_name = LP_DATA[circle_key][language]["title"]
            circle = Circle.objects.filter(
                slug=f"{course_session.course.slug}-lp-circle-{circle_name.lower()}"
            ).first()

            if course_session and circle:
                csu = CourseSessionUser.objects.filter(
                    course_session_id=course_session.id, user_id=user.id
                ).first()
                if csu:
                    csu.expert.add(circle)
                    csu.save()


def get_or_create_users_uk():
    members = [
        _create_or_update_user(
            f"teilnehmer{n}.uk@iterativ.ch",
            f"Teilnehmer{n} üK",
            f"Iterativ{n}",
            PASSWORD,
            "de",
        )
        for n in range(1, 10)
    ]
    trainer = _create_or_update_user(
        "trainer1.uk@iterativ.ch", "Trainer1 üK", "Iterativ1", PASSWORD, "de"
    )
    regionenleiter = _create_or_update_user(
        "regionenleiter1.uk@iterativ.ch",
        "Regionenleiter1 üK",
        "Iterativ1",
        PASSWORD,
        "de",
    )
    return (
        members,
        trainer,
        regionenleiter,
    )


def get_or_create_users_vv():
    members = [
        _create_or_update_user(
            f"teilnehmer{n}.vv@iterativ.ch",
            f"Teilnehmer{n} VV ",
            f"Iterativ{n}",
            PASSWORD,
            "de",
        )
        for n in range(1, 10)
    ]
    member_with_mentor = _create_or_update_user(
        "teilnehmer1.mitlb.vv@iterativ.ch",
        "Teilnehmer1 VV mit LB",
        "Iterativ1",
        PASSWORD,
        "de",
    )
    mentor = _create_or_update_user(
        "lernbegleitung1.vv@iterativ.ch",
        "Lernbegleitung1 VV",
        "Iterativ1",
        PASSWORD,
        "de",
    )
    return members, member_with_mentor, mentor


def _create_or_update_user(email, first_name, last_name, password, language):
    try:
        user = User.objects.get(email=email)
    except User.DoesNotExist:
        user = User(
            email=email,
            username=email,
        )

    user.email = email
    user.first_name = first_name or user.first_name
    user.last_name = last_name or user.last_name
    user.username = email
    user.language = language
    user.set_password(password)
    user.save()
    return user


def create_uk_data(language):
    return {
        "Klasse": IT_UK_TEST_COURSE,
        "ID": IT_UK_TEST_COURSE,
        "Generation": 2024,
        "Region": "Bern",
        "Sprache": language,
        f"Kickoff {TRANSLATIONS[language]['start']}": timezone.make_aware(
            datetime.combine((timezone.now() + timedelta(weeks=2)).date(), time(9, 0))
        ).strftime("%d.%m.%Y, %H:%M"),
        f"Kickoff {TRANSLATIONS[language]['ende']}": timezone.make_aware(
            datetime.combine((timezone.now() + timedelta(weeks=2)).date(), time(16, 0))
        ).strftime("%d.%m.%Y, %H:%M"),
        f"Kickoff {TRANSLATIONS[language]['raum']}": "Raum 1",
        f"Kickoff {TRANSLATIONS[language]['standort']}": "Bern",
        f"Kickoff {TRANSLATIONS[language]['adresse']}": "Musterstrasse 1",
        f"Basis {TRANSLATIONS[language]['start']}": timezone.make_aware(
            datetime.combine((timezone.now() + timedelta(weeks=4)).date(), time(9, 0))
        ).strftime("%d.%m.%Y, %H:%M"),
        f"Basis {TRANSLATIONS[language]['ende']}": timezone.make_aware(
            datetime.combine((timezone.now() + timedelta(weeks=4)).date(), time(16, 0))
        ).strftime("%d.%m.%Y, %H:%M"),
        f"Basis {TRANSLATIONS[language]['raum']}": "Raum 1",
        f"Basis {TRANSLATIONS[language]['standort']}": "Bern",
        f"Basis {TRANSLATIONS[language]['adresse']}": "Musterstrasse 1",
        f"Fahrzeug {TRANSLATIONS[language]['start']}": timezone.make_aware(
            datetime.combine((timezone.now() + timedelta(weeks=6)).date(), time(9, 0))
        ).strftime("%d.%m.%Y, %H:%M"),
        f"Fahrzeug {TRANSLATIONS[language]['ende']}": timezone.make_aware(
            datetime.combine((timezone.now() + timedelta(weeks=6)).date(), time(16, 0))
        ).strftime("%d.%m.%Y, %H:%M"),
        f"Fahrzeug {TRANSLATIONS[language]['raum']}": "Raum 1",
        f"Fahrzeug {TRANSLATIONS[language]['standort']}": "Bern",
        f"Fahrzeug {TRANSLATIONS[language]['adresse']}": "Musterstrasse 1",
        f"Haushalt Teil 1 {TRANSLATIONS[language]['start']}": timezone.make_aware(
            datetime.combine((timezone.now() + timedelta(weeks=8)).date(), time(9, 0))
        ).strftime("%d.%m.%Y, %H:%M"),
        f"Haushalt Teil 1 {TRANSLATIONS[language]['ende']}": timezone.make_aware(
            datetime.combine((timezone.now() + timedelta(weeks=8)).date(), time(16, 0))
        ).strftime("%d.%m.%Y, %H:%M"),
        f"Haushalt Teil 1 {TRANSLATIONS[language]['raum']}": "Raum 1",
        f"Haushalt Teil 1 {TRANSLATIONS[language]['standort']}": "Bern",
        f"Haushalt Teil 1 {TRANSLATIONS[language]['adresse']}": "Musterstrasse 1",
        f"Haushalt Teil 2 {TRANSLATIONS[language]['start']}": timezone.make_aware(
            datetime.combine((timezone.now() + timedelta(weeks=10)).date(), time(9, 0))
        ).strftime("%d.%m.%Y, %H:%M"),
        f"Haushalt Teil 2 {TRANSLATIONS[language]['ende']}": timezone.make_aware(
            datetime.combine((timezone.now() + timedelta(weeks=10)).date(), time(16, 0))
        ).strftime("%d.%m.%Y, %H:%M"),
        f"Haushalt Teil 2 {TRANSLATIONS[language]['raum']}": "Raum 1",
        f"Haushalt Teil 2 {TRANSLATIONS[language]['standort']}": "Bern",
        f"Haushalt Teil 2 {TRANSLATIONS[language]['adresse']}": "Musterstrasse 1",
    }


def create_and_add_to_cs_group(
    course: Course, name: str, course_sessions: list[CourseSession], supervisor: User
):
    region, _ = CourseSessionGroup.objects.get_or_create(
        name=name,
        course=course,
    )

    for cs in course_sessions:
        region.course_session.add(cs)

    region.supervisor.add(supervisor)


def get_vv_course(language: str) -> Course:
    if language == "fr":
        course_id = COURSE_VERSICHERUNGSVERMITTLERIN_FR_ID
    elif language == "it":
        course_id = COURSE_VERSICHERUNGSVERMITTLERIN_IT_ID
    else:
        course_id = COURSE_VERSICHERUNGSVERMITTLERIN_ID

    return Course.objects.get(id=course_id)


def create_or_update_assignment_course_session(cs: CourseSession):
    # not nice but works for now
    for assignment in Assignment.objects.all():
        if assignment.get_course().id == cs.course.id:
            logger.debug(
                "create_course_session_assigments",
                assignment=assignment,
                label="reset_test_courses",
            )
            for lca in assignment.learningcontentassignment_set.all():
                _csa, _created = CourseSessionAssignment.objects.get_or_create(
                    course_session=cs,
                    learning_content=lca,
                )
