import datetime

from app.base.mode import EnrollmentsMode
from app.dependencies import db
from app.examination_schedule.models import ExaminationSchedule, TermOfDefence

from ...factory import (
    ExaminationScheduleFactory,
    GroupFactory,
    StudentFactory,
    ProjectSupervisorFactory,
    TermOfDefenceFactory,
    YearGroupFactory,
)
from ...utils import (
    _test_case_client,
    _test_case_client_without_response,
    assert_model_changes,
    create_many_models,
    create_one_model,
    get_data_of_term_of_defence
)


def test_list_examination_schedule(test_app_with_context) -> None:
    with test_app_with_context.test_client() as client:
        year_group = create_one_model(YearGroupFactory)
        st = create_one_model(StudentFactory, year_group_id=year_group.id)
        create_many_models(23, ExaminationScheduleFactory, year_group_id=year_group.id)
        url = f"/api/students/examination-schedule/year-group/{year_group.id}/?student_id={st.id}"
        data = _test_case_client_without_response(client, url, None, 200, method="get")
        assert len(data.get("examination_schedules")) == 23


def test_list_examination_schedule_if_student_doesnt_exist(test_app_with_context) -> None:
    with test_app_with_context.test_client() as client:
        yg = create_one_model(YearGroupFactory)
        _test_case_client(
            client,
            f"/api/students/examination-schedule/year-group/{yg.id}/?student_id=2",
            None,
            "Not found student!",
            404,
            method="get",
            key="error",
        )


def test_list_term_of_defences(test_app_with_context) -> None:
    with test_app_with_context.test_client() as client:
        year_group = create_one_model(YearGroupFactory)
        st = create_one_model(StudentFactory, year_group_id=year_group.id)
        ex = create_one_model(ExaminationScheduleFactory, year_group_id=year_group.id)
        project_supervisors = create_many_models(13, ProjectSupervisorFactory, year_group_id=year_group.id)
        ps = project_supervisors[0]
        group = create_one_model(GroupFactory, year_group_id=year_group.id, project_supervisor_id=ps.id)
        group.students.append(st)
        db.session.commit()

        term_of_defences = create_many_models(13, TermOfDefenceFactory, examination_schedule_id=ex.id)
        ps_amount = 6
        for i in range(ps_amount):
            term_of_defences[i].members_of_committee.append(ps)
        db.session.commit()

        url = f"/api/students/examination-schedule/{ex.id}/enrollments/?student_id={st.id}"
        data = _test_case_client_without_response(client, url, None, 200, method="get")
        assert len(data.get("term_of_defences")) == ps_amount


def test_list_term_of_defences_if_student_doesnt_exist(test_app_with_context) -> None:
    with test_app_with_context.test_client() as client:
        _test_case_client(
            client,
            "/api/students/examination-schedule/3/enrollments/?student_id=2",
            None,
            "Not found student!",
            404,
            method="get",
            key="error",
        )


def test_assign_your_group_to_term_of_defence(test_app_with_context) -> None:
    with test_app_with_context.test_client() as client:
        year_group = create_one_model(YearGroupFactory)
        ex = create_one_model(ExaminationScheduleFactory, year_group_id=year_group.id,
                              open_enrollments=EnrollmentsMode.OPEN.value)
        ps = create_one_model(ProjectSupervisorFactory, year_group_id=year_group.id)
        st = create_one_model(StudentFactory, year_group_id=year_group.id)
        td = create_one_model(TermOfDefenceFactory, examination_schedule_id=ex.id)
        group = create_one_model(GroupFactory, year_group_id=year_group.id, project_supervisor_id=ps.id)
        td.members_of_committee.append(ps)
        group.students.append(st)
        db.session.commit()

        _test_case_client(
            client,
            f"/api/students/{ex.id}/enrollments/{td.id}/",
            {"student_id": st.id},
            "You have just assigned the group for this exam date!",
            201,
            method="post",
        )


def test_assign_your_group_to_term_of_defence_if_student_doesnt_exist(
        test_app_with_context,
) -> None:
    with test_app_with_context.test_client() as client:
        _test_case_client(
            client,
            "/api/students/3/enrollments/1/",
            {"student_id": 2},
            "Not found student!",
            404,
            method="post",
            key="error",
        )


def test_assign_your_group_to_term_of_defence_if_term_of_defence_doesnt_exist(
        test_app_with_context,
) -> None:
    with test_app_with_context.test_client() as client:
        st = create_one_model(StudentFactory)
        _test_case_client(
            client,
            "/api/students/3/enrollments/1/",
            {"student_id": st.id},
            "Term of defence not found!",
            404,
            method="post",
            key="error",
        )


def test_assign_your_group_to_term_of_defence_if_enrollments_havent_started_yet(
        test_app_with_context,
) -> None:
    with test_app_with_context.test_client() as client:
        year_group = create_one_model(YearGroupFactory)
        ex = create_one_model(ExaminationScheduleFactory, year_group_id=year_group.id)
        td = create_one_model(TermOfDefenceFactory, examination_schedule_id=ex.id)
        st = create_one_model(StudentFactory, year_group_id=year_group.id)
        _test_case_client(
            client,
            f"/api/students/{ex.id}/enrollments/{td.id}/",
            {"student_id": st.id},
            "Enrollments is closed! You have been delayed!",
            400,
            method="post",
            key="error",
        )


def test_assign_your_group_to_term_of_defence_if_you_dont_have_group(
        test_app_with_context,
) -> None:
    with test_app_with_context.test_client() as client:
        year_group = create_one_model(YearGroupFactory)
        ex = create_one_model(ExaminationScheduleFactory, year_group_id=year_group.id,
                              open_enrollments=EnrollmentsMode.OPEN.value)
        td = create_one_model(TermOfDefenceFactory, examination_schedule_id=ex.id)
        st = create_one_model(StudentFactory, year_group_id=year_group.id)
        _test_case_client(
            client,
            f"/api/students/{ex.id}/enrollments/{td.id}/",
            {"student_id": st.id},
            "You don't have a group or your group doesn't have an assigned project supervisor!",
            400,
            method="post",
            key="error",
        )


def test_assign_your_group_to_term_of_defence_if_your_group_has_already_assigned_to_any_term_of_defence(
        test_app_with_context,
) -> None:
    with test_app_with_context.test_client() as client:
        year_group = create_one_model(YearGroupFactory)
        ex = create_one_model(ExaminationScheduleFactory, year_group_id=year_group.id,
                              open_enrollments=EnrollmentsMode.OPEN.value)
        td = create_one_model(TermOfDefenceFactory, examination_schedule_id=ex.id)
        st = create_one_model(StudentFactory, year_group_id=year_group.id)
        ps = create_one_model(ProjectSupervisorFactory, year_group_id=year_group.id)
        group = create_one_model(GroupFactory, year_group_id=year_group.id, project_supervisor_id=ps.id)
        td.group_id = group.id
        group.students.append(st)
        db.session.commit()

        _test_case_client(
            client,
            f"/api/students/{ex.id}/enrollments/{td.id}/",
            {"student_id": st.id},
            "Your group has already assigned to any exam date!",
            400,
            method="post",
            key="error",
        )

def test_assign_your_group_to_term_of_defence_if_your_project_supervisor_is_not_in_committee(
        test_app_with_context,
) -> None:
    with test_app_with_context.test_client() as client:
        year_group = create_one_model(YearGroupFactory)
        ex = create_one_model(ExaminationScheduleFactory, year_group_id=year_group.id,
                              open_enrollments=EnrollmentsMode.OPEN.value)
        td = create_one_model(TermOfDefenceFactory, examination_schedule_id=ex.id)
        st = create_one_model(StudentFactory, year_group_id=year_group.id)
        ps = create_one_model(ProjectSupervisorFactory, year_group_id=year_group.id)
        group = create_one_model(GroupFactory, year_group_id=year_group.id, project_supervisor_id=ps.id)
        group.students.append(st)
        db.session.commit()

        _test_case_client(
            client,
            f"/api/students/{ex.id}/enrollments/{td.id}/",
            {"student_id": st.id},
            "Your project supervisor is not in committee!",
            400,
            method="post",
            key="error",
        )

def test_delete_your_group_from_term_of_defence(test_app_with_context) -> None:
    with test_app_with_context.test_client() as client:
        year_group = create_one_model(YearGroupFactory)
        ex = create_one_model(ExaminationScheduleFactory, year_group_id=year_group.id,
                              open_enrollments=EnrollmentsMode.OPEN.value)
        ps = create_one_model(ProjectSupervisorFactory, year_group_id=year_group.id)
        st = create_one_model(StudentFactory, year_group_id=year_group.id)
        group = create_one_model(GroupFactory, year_group_id=year_group.id, project_supervisor_id=ps.id)
        td = create_one_model(TermOfDefenceFactory, examination_schedule_id=ex.id, group_id=group.id)
        td.members_of_committee.append(ps)
        group.students.append(st)
        db.session.commit()

        _test_case_client(
            client,
            f"/api/students/{ex.id}/enrollments/{td.id}/",
            {"student_id": st.id},
            "You have just removed the group for this exam date!",
            200,
            method="delete",
        )
def test_delete_your_group_from_term_of_defence_if_student_doesnt_exist(
        test_app_with_context,
) -> None:
    with test_app_with_context.test_client() as client:
        _test_case_client(
            client,
            "/api/students/3/enrollments/1/",
            {"student_id": 2},
            "Not found student!",
            404,
            method="delete",
            key="error",
        )

def test_delete_your_group_from_term_of_defence_if_term_of_defence_doesnt_exist(
        test_app_with_context,
) -> None:
    with test_app_with_context.test_client() as client:
        st = create_one_model(StudentFactory)
        _test_case_client(
            client,
            "/api/students/3/enrollments/1/",
            {"student_id": st.id},
            "Not found term of defence!",
            404,
            method="delete",
            key="error",
        )

def test_assign_your_group_to_term_of_defence_if_you_try_delete_not_your_group(
        test_app_with_context,
) -> None:
    with test_app_with_context.test_client() as client:
        year_group = create_one_model(YearGroupFactory)
        ex = create_one_model(ExaminationScheduleFactory, year_group_id=year_group.id,
                              open_enrollments=EnrollmentsMode.OPEN.value)
        td = create_one_model(TermOfDefenceFactory, examination_schedule_id=ex.id)
        st = create_one_model(StudentFactory, year_group_id=year_group.id)
        ps = create_one_model(ProjectSupervisorFactory, year_group_id=year_group.id)
        group = create_one_model(GroupFactory, year_group_id=year_group.id, project_supervisor_id=ps.id)
        td.group_id = group.id
        db.session.commit()

        _test_case_client(
            client,
            f"/api/students/{ex.id}/enrollments/{td.id}/",
            {"student_id": st.id},
            "You are not assigned to this group!",
            400,
            method="delete",
            key="error",
        )