# Copyright 2026 4f4d
# Licensed under the Apache License, Version 2.0

"""Tests for f1radio.utils."""

import pytest
from datetime import timedelta

from f1radio.utils import (
    fuzzy_match_race,
    parse_time,
    format_duration,
    resolve_session_type,
    session_relative_time,
    driver_code_to_number,
    driver_number_to_info,
)


class TestResolveSessionType:
    def test_abbreviations(self):
        assert resolve_session_type("R") == "Race"
        assert resolve_session_type("Q") == "Qualifying"
        assert resolve_session_type("FP1") == "Practice 1"
        assert resolve_session_type("FP2") == "Practice 2"
        assert resolve_session_type("FP3") == "Practice 3"
        assert resolve_session_type("S") == "Sprint"
        assert resolve_session_type("SQ") == "Sprint Qualifying"

    def test_case_insensitive(self):
        assert resolve_session_type("r") == "Race"
        assert resolve_session_type("fp1") == "Practice 1"

    def test_full_name(self):
        assert resolve_session_type("Race") == "Race"
        assert resolve_session_type("QUALIFYING") == "Qualifying"

    def test_invalid(self):
        with pytest.raises(ValueError, match="Unknown session type"):
            resolve_session_type("XYZ")


class TestFuzzyMatchRace:
    def test_exact_match(self):
        names = ["Italian Grand Prix", "Belgian Grand Prix", "Dutch Grand Prix"]
        assert fuzzy_match_race("Italian Grand Prix", names) == "Italian Grand Prix"

    def test_substring_match(self):
        names = ["Italian Grand Prix", "Belgian Grand Prix"]
        assert fuzzy_match_race("Italian", names) == "Italian Grand Prix"

    def test_circuit_name(self):
        names = ["Monza", "Spa-Francorchamps", "Zandvoort"]
        assert fuzzy_match_race("Monza", names) == "Monza"

    def test_fuzzy_match(self):
        names = ["Italian Grand Prix", "Belgian Grand Prix", "Dutch Grand Prix"]
        result = fuzzy_match_race("Itlian", names)
        assert result == "Italian Grand Prix"

    def test_no_match(self):
        names = ["Italian Grand Prix"]
        assert fuzzy_match_race("zzzzz", names, threshold=90) is None

    def test_empty_list(self):
        assert fuzzy_match_race("Monza", []) is None

    def test_case_insensitive(self):
        names = ["Italian Grand Prix"]
        assert fuzzy_match_race("italian grand prix", names) == "Italian Grand Prix"


class TestParseTime:
    def test_hhmmss(self):
        result = parse_time("01:32:15")
        assert result == timedelta(hours=1, minutes=32, seconds=15)

    def test_hhmmss_with_millis(self):
        result = parse_time("01:32:15.456")
        assert result.total_seconds() == pytest.approx(5535.456, abs=0.001)

    def test_mmss(self):
        result = parse_time("32:15")
        assert result == timedelta(minutes=32, seconds=15)

    def test_lap_time_format(self):
        result = parse_time("1:32.456")
        assert result.total_seconds() == pytest.approx(92.456, abs=0.001)

    def test_zero(self):
        result = parse_time("00:00:00")
        assert result == timedelta(0)

    def test_invalid(self):
        with pytest.raises(ValueError, match="Unrecognized time format"):
            parse_time("invalid")


class TestFormatDuration:
    def test_basic(self):
        assert format_duration(5535) == "01:32:15"

    def test_zero(self):
        assert format_duration(0) == "00:00:00"

    def test_hours(self):
        assert format_duration(7200) == "02:00:00"


class TestSessionRelativeTime:
    def test_basic(self):
        result = session_relative_time(
            "2023-09-03T13:32:15+00:00",
            "2023-09-03T13:00:00+00:00",
        )
        assert result == "00:32:15"

    def test_before_start(self):
        result = session_relative_time(
            "2023-09-03T12:59:00+00:00",
            "2023-09-03T13:00:00+00:00",
        )
        assert result == "00:00:00"  # Clamped to 0


class TestDriverLookup:
    def test_code_to_number(self, mock_drivers):
        assert driver_code_to_number("VER", mock_drivers) == 1
        assert driver_code_to_number("HAM", mock_drivers) == 44

    def test_code_to_number_not_found(self, mock_drivers):
        assert driver_code_to_number("XXX", mock_drivers) is None

    def test_number_to_info(self, mock_drivers):
        code, name, team = driver_number_to_info(1, mock_drivers)
        assert code == "VER"
        assert name == "Max Verstappen"
        assert team == "Red Bull Racing"

    def test_number_to_info_not_found(self, mock_drivers):
        code, name, team = driver_number_to_info(999, mock_drivers)
        assert code == "???"
