import json
import datetime

from django.http import HttpResponse
from django.urls import reverse
import pytest
from atlas.models import Case, CaseCollection, Finding, Condition
#from atlas.views import GenericExamViews
from pytest_django.asserts import assertRedirects, assertContains, assertQuerySetEqual
from django.test import TestCase


#@pytest.mark.django_db
def test_create_condition(db):
    abnormality = Condition.objects.create(name="Abnorm")
    assert abnormality.name == "Abnorm"


def test_condition_tree_structure(db):
    parent = Condition.objects.create(name="parent")

    child1 = Condition.objects.create(name="child1")
    child2 = Condition.objects.create(name="child2")

    parent.child.set([child1, child2])

    child1_1 = Condition.objects.create(name="child1_1")
    child1_2 = Condition.objects.create(name="child1_2")

    child1.child.set([child1_1, child1_2])

    assert len(parent.get_children()) == 2
    assert len(child1.get_children()) == 2

    assert len(child1.get_parents()) == 1
    assert parent in child1.get_parents()

    assert len(child2.get_parents()) == 1
    assert parent in child2.get_parents()


#@pytest.fixture
#def create_basic_user(db, django_user_model):
#    return django_user_model.objects.create_superuser("basicuser", "ross@xkjq.uk", "password")
#
#@pytest.fixture
#def create_exam(db):
#    return Exam.objects.create(name="test exam", exam_mode=True)
#
#def test_exam_creation(create_exam):
#    exams = Exam.objects.filter(name="test exam")
#    assert exams.exists()
#
#    exam = exams.first()
#
#    assert exam.time_limit == 35 * 60
#
#def test_exam_list(rf, admin_user, create_exam):
#    request = rf.get('/rapids/exam/')
#    # Remember that when using RequestFactory, the request does not pass
#    # through middleware. If your view expects fields such as request.user to be
#    # set, you need to set them explicitly.
#    # The following line sets request.user to an admin user.
#    request.user = admin_user
#    response = GenericExamViews.exam_list(request)
#    #print(response)
#    assert response.status_code == 200
#
#def test_exam_active_admin(rf, admin_user, create_exam, client):
#    request = rf.get(reverse('rapids:active_exams'))
#    request.user = admin_user
#    response = GenericExamViews.active_exams(request)
#    print(response.content)
#    assert response.status_code == 200
#
#def test_exam_active_basic_user(create_basic_user, create_exam, client):
#    client.login(username="basicuser", password="password")
#    response = client.get(reverse('rapids:active_exams'))
#    print(response.content)
#    assert response.status_code == 200

def test_create_case(db, create_case):
    case = create_case
    assert case.title == "Sample Case"

def test_create_series(db, create_series):
    series = create_series
    assert series



def test_collection(db, create_case_collection, create_case, make_case, client, create_user):
    collection: CaseCollection = create_case_collection

    # create some cases
    case1 = create_case
    case2 = make_case()
    case3 = make_case(title="Case 3")
    case4 = make_case(title="Case 4")

    collection.cases.set([case1, case2, case3, case4])

    case5 = make_case(title="Case 5")

    assert collection.cases.all().count() == 4

    collection.add_case(case5)

    assert collection.cases.all().count() == 5

    assert collection.get_case_by_index(0) == case1
    assert collection.get_case_by_index(1) == case2
    assert collection.get_case_by_index(2) == case3
    assert collection.get_case_by_index(3) == case4
    assert collection.get_case_by_index(4) == case5

    assert collection.get_absolute_url() == reverse("atlas:collection_detail", kwargs={"pk": collection.pk})

    assert collection.get_take_url() == reverse("atlas:collection_take_start", kwargs={"pk": collection.pk})

    start_order = collection.get_cases()

    new_order = [
        case5.pk,
        case1.pk,
        case2.pk,
        case3.pk,
        case4.pk
    ]
    response: HttpResponse = client.post(reverse("atlas:exam_json_edit", kwargs={"pk":collection.pk} ), json=new_order, follow=True)
    # Check that sorting the exam works

    # First attempt is not logged in
    from urllib.parse import quote
    expected_next = quote(reverse("atlas:exam_json_edit", kwargs={"pk": collection.pk}))
    assertRedirects(response, f"{reverse('login')}?next={expected_next}")

    client.force_login(create_user)

    # Random user cannot modify order
    response: HttpResponse = client.post(reverse("atlas:exam_json_edit", kwargs={"pk":collection.pk} ), json=new_order, follow=True)
    assert response.status_code == 403

    assertQuerySetEqual(start_order , collection.get_cases())

    # Once the user has been made an author, they can modify the order
    collection.add_author(create_user)
    response: HttpResponse = client.post(reverse("atlas:exam_json_edit", kwargs={"pk":collection.pk} ), data={"set_exam_order" : json.dumps(new_order)}, follow=True)
    assert response.status_code == 200

    assert collection.get_cases().count() == 5
    assert collection.get_case_by_index(0) == case5
    assert collection.get_case_by_index(1) == case1


@pytest.mark.django_db
def test_linked_cases_overview_can_copy_study_date_to_chain(client, create_user, make_case):
    user = create_user
    case1 = make_case(title="Case 1")
    case2 = make_case(title="Case 2")
    case2.previous_case = case1
    case2.save(update_fields=["previous_case"])

    case1.author.add(user)
    case2.author.add(user)

    client.force_login(user)

    response = client.post(
        reverse("atlas:linked_cases_overview", kwargs={"case_id": case1.pk}),
        data={
            f"study_date_{case1.pk}": "2026-01-10",
            f"study_date_{case2.pk}": "2026-01-12",
            "apply_to_all_from": str(case1.pk),
        },
        follow=True,
    )

    assert response.status_code == 200
    case1.refresh_from_db()
    case2.refresh_from_db()

    assert str(case1.study_date) == "2026-01-10"
    assert str(case2.study_date) == "2026-01-10"


@pytest.mark.django_db
def test_case_save_auto_populates_study_date_when_missing(monkeypatch, make_case):
    expected_date = datetime.date(2026, 2, 14)
    monkeypatch.setattr(Case, "_get_series_study_date", lambda self: expected_date)

    case = make_case(title="Autodate Case")
    case.study_date = None
    case.save(update_fields=["study_date"])
    case.refresh_from_db()

    assert case.study_date == expected_date


@pytest.mark.django_db
def test_case_save_preserves_manual_study_date(monkeypatch, make_case):
    manual_date = datetime.date(2026, 3, 1)
    monkeypatch.setattr(Case, "_get_series_study_date", lambda self: datetime.date(2026, 4, 1))

    case = make_case(title="Manual Date Case")
    case.study_date = manual_date
    case.save(update_fields=["study_date"])
    case.refresh_from_db()

    assert case.study_date == manual_date


@pytest.mark.django_db
def test_linked_cases_editor_is_hidden_until_requested(client, create_user, make_case):
    user = create_user
    case1 = make_case(title="Case 1")
    case2 = make_case(title="Case 2")
    case2.previous_case = case1
    case2.save(update_fields=["previous_case"])

    case1.author.add(user)
    case2.author.add(user)

    client.force_login(user)

    response_default = client.get(
        reverse("atlas:linked_cases_overview", kwargs={"case_id": case1.pk})
    )
    assert response_default.status_code == 200
    assertContains(response_default, "Open case series editor")
    assert "Case Series Editor" not in response_default.content.decode("utf-8")

    response_with_editor = client.get(
        reverse("atlas:linked_cases_overview", kwargs={"case_id": case1.pk}) + "?show_editor=1"
    )
    assert response_with_editor.status_code == 200
    assertContains(response_with_editor, "Case Series Editor")


@pytest.mark.django_db
def test_linked_cases_study_dates_editor_is_hidden_until_requested(client, create_user, make_case):
    user = create_user
    case1 = make_case(title="Case 1")
    case2 = make_case(title="Case 2")
    case2.previous_case = case1
    case2.save(update_fields=["previous_case"])

    case1.author.add(user)
    case2.author.add(user)

    client.force_login(user)

    response_default = client.get(
        reverse("atlas:linked_cases_overview", kwargs={"case_id": case1.pk})
    )
    assert response_default.status_code == 200
    assertContains(response_default, "Open study dates editor")
    assert "Study Dates" not in response_default.content.decode("utf-8")

    response_with_editor = client.get(
        reverse("atlas:linked_cases_overview", kwargs={"case_id": case1.pk}) + "?show_dates=1"
    )
    assert response_with_editor.status_code == 200
    assertContains(response_with_editor, "Study Dates")


@pytest.mark.django_db
def test_linked_case_card_shows_scaled_relative_timeline_label(client, create_user, make_case):
    user = create_user
    case1 = make_case(title="Case 1")
    case2 = make_case(title="Case 2")
    case2.previous_case = case1
    case2.study_date = datetime.date(2028, 1, 1)
    case2.save(update_fields=["previous_case", "study_date"])
    case1.study_date = datetime.date(2026, 1, 1)
    case1.save(update_fields=["study_date"])

    case1.author.add(user)
    case2.author.add(user)

    client.force_login(user)

    response = client.get(
        reverse("atlas:linked_cases_overview", kwargs={"case_id": case1.pk})
    )
    assert response.status_code == 200
    assertContains(response, "Timeline +2 years")
