from unittest.mock import patch

from discgolf.models import DiscGolfCourse
from discgolf.utils import _parse_udisc_datetime, import_udisc_csv
from people.models import Person
from scrobbles.models import Scrobble


class TestParserHelpers:
    def test_parse_udisc_datetime(self):
        dt = _parse_udisc_datetime("Jun 15, 2026 10:00 AM")
        assert dt is not None
        assert dt.year == 2026
        assert dt.month == 6
        assert dt.day == 15
        assert dt.hour == 10
        assert dt.minute == 0

    def test_parse_udisc_datetime_date_only(self):
        dt = _parse_udisc_datetime("Jun 15, 2026")
        assert dt is not None
        assert dt.year == 2026


class TestImportUdiscCSV:
    def test_import_singles_creates_course(self, user, udisc_singles_csv_file):
        import_udisc_csv(udisc_singles_csv_file, user.id)
        course = DiscGolfCourse.objects.filter(title="Maple Hill").first()
        assert course is not None
        assert course.layout_name == "Mountains"
        assert course.number_of_holes == 3
        assert course.par_total == 9
        assert course.par_per_hole == {"hole_1": 3, "hole_2": 3, "hole_3": 3}

    def test_import_singles_creates_scrobble(self, user, udisc_singles_csv_file):
        import_udisc_csv(udisc_singles_csv_file, user.id)
        assert Scrobble.objects.filter(source="uDisc").count() == 1

    def test_import_singles_logdata(self, user, udisc_singles_csv_file):
        import_udisc_csv(udisc_singles_csv_file, user.id)
        scrobble = Scrobble.objects.filter(source="uDisc").first()
        log = scrobble.log
        assert log["course_name"] == "Maple Hill"
        assert log["par"] == 9
        assert log["round_type"] == "Singles"
        assert "Alice" in log["scores"]
        assert "Bob" in log["scores"]
        assert log["scores"]["Alice"]["total"] == 9
        assert log["scores"]["Bob"]["total"] == 12

    def test_import_singles_creates_people(self, user, udisc_singles_csv_file):
        import_udisc_csv(udisc_singles_csv_file, user.id)
        assert Person.objects.filter(name="Alice").exists()
        assert Person.objects.filter(name="Bob").exists()

    def test_import_teams_creates_scrobble(self, user, udisc_teams_csv_file):
        import_udisc_csv(udisc_teams_csv_file, user.id)
        assert Scrobble.objects.filter(source="uDisc").count() == 1

    def test_import_teams_logdata(self, user, udisc_teams_csv_file):
        import_udisc_csv(udisc_teams_csv_file, user.id)
        scrobble = Scrobble.objects.filter(source="uDisc").first()
        assert scrobble.log["round_type"] == "Teams"
        alice_bob = scrobble.log["scores"]["Alice+Bob"]
        assert "person_ids" in alice_bob
        assert len(alice_bob["person_ids"]) == 2

    def test_import_creates_team_people(self, user, udisc_teams_csv_file):
        import_udisc_csv(udisc_teams_csv_file, user.id)
        assert Person.objects.filter(name="Alice").exists()
        assert Person.objects.filter(name="Bob").exists()
        assert Person.objects.filter(name="Charlie").exists()
        assert Person.objects.filter(name="Diana").exists()

    def test_import_teams_par_per_hole(self, user, udisc_teams_csv_file):
        import_udisc_csv(udisc_teams_csv_file, user.id)
        course = DiscGolfCourse.objects.get(title="Maple Hill")
        assert course.par_per_hole == {"hole_1": 3, "hole_2": 3, "hole_3": 3}

    def test_import_no_par_returns_empty(self, user, udisc_csv_no_par_file):
        result = import_udisc_csv(udisc_csv_no_par_file, user.id)
        assert result == []

    def test_import_empty_csv(self, user, db):
        import tempfile

        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".csv", delete=False, encoding="utf-8-sig"
        ) as f:
            f.write("PlayerName,CourseName,LayoutName,StartDate,Hole1,Total\n")
            path = f.name

        result = import_udisc_csv(path, user.id)
        assert result == []

    def test_import_idempotent(self, user, udisc_singles_csv_file):
        import_udisc_csv(udisc_singles_csv_file, user.id)
        import_udisc_csv(udisc_singles_csv_file, user.id)
        assert DiscGolfCourse.objects.filter(title="Maple Hill").count() == 1
        assert Scrobble.objects.filter(source="uDisc").count() == 2

    def test_import_course_defaults_only_on_create(
        self, user, udisc_singles_csv_file
    ):
        import_udisc_csv(udisc_singles_csv_file, user.id)
        course = DiscGolfCourse.objects.get(title="Maple Hill")
        assert course.layout_name == "Mountains"

        course.layout_name = "Updated"
        course.save()

        import_udisc_csv(udisc_singles_csv_file, user.id)
        course.refresh_from_db()
        assert course.layout_name == "Updated"

    @patch("discgolf.utils.ScrobbleNtfyNotification")
    def test_import_sends_notification(self, mock_notification_class, user, udisc_singles_csv_file):
        import_udisc_csv(udisc_singles_csv_file, user.id)
        mock_notification_class.assert_called_once()
        mock_notification_class.return_value.send.assert_called_once()

    def test_import_hole_scores_per_player(self, user, udisc_singles_csv_file):
        import_udisc_csv(udisc_singles_csv_file, user.id)
        scrobble = Scrobble.objects.filter(source="uDisc").first()
        alice = scrobble.log["scores"]["Alice"]
        assert alice["hole_1"] == 4
        assert alice["hole_2"] == 2
        assert alice["hole_3"] == 3
        bob = scrobble.log["scores"]["Bob"]
        assert bob["hole_1"] == 3
        assert bob["hole_2"] == 4
        assert bob["hole_3"] == 5

    def test_import_record_error_on_bad_data(self, user, db):
        import tempfile

        content = """PlayerName,CourseName,LayoutName,StartDate,Hole1,Hole2,Hole3,Total
Par,,Mountains,"Jun 15, 2026 10:00 AM",3,3,3,9
"""
        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".csv", delete=False, encoding="utf-8-sig"
        ) as f:
            f.write(content)
            path = f.name

        errors = []
        result = import_udisc_csv(path, user.id, record_error=errors.append)
        assert len(result) == 1
        course = DiscGolfCourse.objects.first()
        assert course.title == ""
