import pytest

from fasr.utils.metric import compute_char_error_rate, match_token, streaming_delay


class TestComputeCharErrorRate:
    def test_identical_strings(self):
        assert compute_char_error_rate("你好世界", "你好世界") == 0.0

    def test_completely_different(self):
        cer = compute_char_error_rate("abc", "xyz")
        assert cer == 1.0

    def test_partial_match(self):
        cer = compute_char_error_rate("你好世界", "你好地球")
        assert 0 < cer < 1

    def test_empty_both(self):
        cer = compute_char_error_rate("", "")
        assert cer == 1.0

    def test_empty_target(self):
        cer = compute_char_error_rate("hello", "")
        assert cer == 0.0

    def test_empty_source(self):
        cer = compute_char_error_rate("", "hello")
        assert cer > 0

    def test_ignore_space(self):
        cer = compute_char_error_rate("你 好", "你好", ignore_space=True)
        assert cer == 0.0

    def test_keep_space(self):
        cer_ignore = compute_char_error_rate("你 好", "你好", ignore_space=True)
        cer_keep = compute_char_error_rate("你 好", "你好", ignore_space=False)
        assert cer_keep >= cer_ignore

    def test_ignore_punctuation(self):
        cer = compute_char_error_rate("你好，世界！", "你好世界", ignore_punc=True)
        assert cer == 0.0

    def test_keep_punctuation(self):
        cer = compute_char_error_rate("你好，世界！", "你好世界", ignore_punc=False)
        assert cer > 0

    def test_insertion(self):
        cer = compute_char_error_rate("你好啊世界", "你好世界")
        assert cer > 0

    def test_deletion(self):
        cer = compute_char_error_rate("你好", "你好世界")
        assert cer > 0

    def test_substitution(self):
        cer = compute_char_error_rate("你坏世界", "你好世界")
        assert cer > 0


class TestMatchToken:
    def test_identical(self):
        matched = match_token("abc", "abc")
        assert len(matched) == 3
        assert matched == [(0, 0), (1, 1), (2, 2)]

    def test_insertion(self):
        matched = match_token("axbc", "abc")
        assert len(matched) == 3

    def test_deletion(self):
        matched = match_token("ac", "abc")
        assert len(matched) == 2

    def test_substitution(self):
        matched = match_token("axc", "abc")
        assert len(matched) == 2

    def test_case_insensitive(self):
        matched = match_token("ABC", "abc")
        assert len(matched) == 3

    def test_empty_strings(self):
        matched = match_token("", "")
        assert matched == []


class TestStreamingDelay:
    def test_basic(self):
        t_send = [
            {"token": "a", "timestamp": 0.1},
            {"token": "b", "timestamp": 0.2},
            {"token": "c", "timestamp": 0.3},
        ]
        t_response = [
            {"token": "a", "timestamp": 0.3},
            {"token": "b", "timestamp": 0.4},
            {"token": "c", "timestamp": 0.5},
        ]
        delay = streaming_delay(t_send, t_response)
        assert isinstance(delay, float)
        assert abs(delay - 0.2) < 0.01

    def test_return_results(self):
        t_send = [
            {"token": "a", "timestamp": 0.1},
            {"token": "b", "timestamp": 0.2},
        ]
        t_response = [
            {"token": "a", "timestamp": 0.3},
            {"token": "b", "timestamp": 0.4},
        ]
        results = streaming_delay(t_send, t_response, return_results=True)
        assert isinstance(results, list)
        assert len(results) == 2
        assert results[0]["token"] == "a"
        assert abs(results[0]["delay"] - 0.2) < 0.01

    def test_partial_match(self):
        t_send = [
            {"token": "a", "timestamp": 0.1},
            {"token": "b", "timestamp": 0.2},
            {"token": "c", "timestamp": 0.3},
        ]
        t_response = [
            {"token": "a", "timestamp": 0.3},
            {"token": "c", "timestamp": 0.5},
        ]
        results = streaming_delay(t_send, t_response, return_results=True)
        assert len(results) == 2
