"""Unit tests: URL extraction helpers and ChatHistory."""

from __future__ import annotations

import pytest

from seaart._enums import Role
from seaart.helpers import (
    ChatHistory,
    CharacterLink,
    ModelLink,
    extract_character_link,
    extract_model_link,
    extract_task_id_from_image_url,
)


# ── extract_character_link ───────────────────────────────────────────────────


class TestExtractCharacterLink:
    def test_chat_url_with_session(self) -> None:
        url = "https://www.seaart.ai/character/chat/abc123?s_id=sess456"
        result = extract_character_link(url)
        assert result == CharacterLink(character_id="abc123", session_id="sess456")

    def test_chat_url_without_session(self) -> None:
        url = "https://www.seaart.ai/character/chat/abc123"
        result = extract_character_link(url)
        assert result == CharacterLink(character_id="abc123", session_id=None)

    def test_details_url(self) -> None:
        url = "https://www.seaart.ai/character/details/xyz789"
        result = extract_character_link(url)
        assert result == CharacterLink(character_id="xyz789", session_id=None)

    def test_invalid_path(self) -> None:
        assert extract_character_link("https://www.seaart.ai/models/detail/x") is None

    def test_no_character_in_path(self) -> None:
        assert extract_character_link("https://example.com/foo/bar") is None

    def test_character_but_wrong_action(self) -> None:
        assert (
            extract_character_link("https://www.seaart.ai/character/unknown/abc")
            is None
        )

    def test_character_but_no_id(self) -> None:
        assert extract_character_link("https://www.seaart.ai/character/chat") is None

    def test_whitespace_stripped(self) -> None:
        url = "  https://www.seaart.ai/character/chat/abc123  "
        result = extract_character_link(url)
        assert result is not None
        assert result.character_id == "abc123"


# ── extract_model_link ───────────────────────────────────────────────────────


class TestExtractModelLink:
    def test_detail_url(self) -> None:
        url = "https://www.seaart.ai/models/detail/model123"
        result = extract_model_link(url)
        assert result == ModelLink(model_no="model123")

    def test_query_params(self) -> None:
        url = "https://www.seaart.ai/create/image?id=m1&model_ver_no=v2"
        result = extract_model_link(url)
        assert result == ModelLink(model_no="m1", model_ver_no="v2")

    def test_query_params_no_ver(self) -> None:
        url = "https://www.seaart.ai/create/image?id=m1"
        result = extract_model_link(url)
        assert result == ModelLink(model_no="m1", model_ver_no=None)

    def test_unrecognized_url(self) -> None:
        assert extract_model_link("https://example.com/other/path") is None

    def test_detail_missing_model_no(self) -> None:
        assert extract_model_link("https://www.seaart.ai/models/detail") is None


# ── extract_task_id_from_image_url ───────────────────────────────────────────


class TestExtractTaskId:
    def test_cdn_url(self) -> None:
        url = "https://image.cdn2.seaart.me/2026-02-25/d6fhvcte878c73fhuu50/abc_high.webp"
        assert extract_task_id_from_image_url(url) == "d6fhvcte878c73fhuu50"

    def test_temp_convert_url(self) -> None:
        url = "https://image.cdn2.seaart.me/temp-convert-webp/highwebp/2025-07-04/d1k5dlte878c73c2cmu0/file.webp"
        assert extract_task_id_from_image_url(url) == "d1k5dlte878c73c2cmu0"

    def test_static_upload_returns_none(self) -> None:
        url = "https://image.cdn2.seaart.me/upload/static/20260224/abc_high.webp"
        assert extract_task_id_from_image_url(url) is None

    def test_short_path_returns_none(self) -> None:
        assert extract_task_id_from_image_url("https://cdn.example.com/file.webp") is None

    def test_numeric_segment_returns_none(self) -> None:
        url = "https://image.cdn2.seaart.me/2026-02-25/20260225/file.webp"
        assert extract_task_id_from_image_url(url) is None


# ── ChatHistory ──────────────────────────────────────────────────────────────


class TestChatHistory:
    def test_user_and_ai(self) -> None:
        h = ChatHistory()
        h.user("hello").ai("world")
        assert len(h) == 2

    def test_iteration(self) -> None:
        h = ChatHistory().user("a").ai("b")
        items = list(h)
        assert items[0] == (Role.USER, "a", "")
        assert items[1] == (Role.ASSISTANT, "b", "")

    def test_chaining(self) -> None:
        h = ChatHistory().user("a").ai("b").user("c")
        assert len(h) == 3

    def test_delete_last(self) -> None:
        h = ChatHistory().user("a").ai("b").user("c")
        h.delete_last(2)
        assert len(h) == 1

    def test_clear(self) -> None:
        h = ChatHistory().user("a").ai("b")
        h.clear()
        assert len(h) == 0

    def test_copy_independent(self) -> None:
        h = ChatHistory().user("a")
        h2 = h.copy()
        h2.user("b")
        assert len(h) == 1
        assert len(h2) == 2

    def test_iadd(self) -> None:
        h1 = ChatHistory().user("a")
        h2 = ChatHistory().ai("b")
        h1 += h2
        assert len(h1) == 2

    def test_add(self) -> None:
        h1 = ChatHistory().user("a")
        h2 = ChatHistory().ai("b")
        h3 = h1 + h2
        assert len(h3) == 2
        assert len(h1) == 1  # original unchanged

    def test_add_string_requires_role(self) -> None:
        h = ChatHistory()
        with pytest.raises(ValueError, match="role is required"):
            h.add("hello")

    def test_add_string_with_role(self) -> None:
        h = ChatHistory()
        h.add("hello", role=Role.USER)
        assert len(h) == 1

    def test_add_chat_history(self) -> None:
        h1 = ChatHistory().user("a")
        h2 = ChatHistory().ai("b")
        h1.add(h2)
        assert len(h1) == 2

    def test_to_input(self) -> None:
        h = ChatHistory().user("a", msg_id="m1").ai("b")
        inp = h.to_input()
        assert isinstance(inp, list)
        assert len(inp) == 2

    def test_repr(self) -> None:
        h = ChatHistory().user("a")
        assert "ChatHistory" in repr(h)
