"""
Tests for knowledge API.
"""

from unittest.mock import Mock, patch

import pytest

from getbiji_box import GetBijiClient
from getbiji_box.exceptions import ValidationError
from getbiji_box.models import FollowListResult, Knowledge, KnowledgeListResult, ResourceListResult


class TestKnowledgeAPI:
    """Test cases for KnowledgeAPI class."""

    def test_knowledge_property(self):
        """Test getting knowledge API from client."""
        client = GetBijiClient(token="test_token")
        knowledge = client.knowledge
        assert knowledge is not None

    @patch("getbiji_box.client.GetBijiClient.post")
    def test_create_knowledge_base(self, mock_post):
        """Test creating a knowledge base."""
        mock_response = Mock()
        mock_response.json.return_value = {
            "h": {"c": 0},
            "c": {
                "id": 123,
                "id_alias": "kb123",
                "name": "My Knowledge Base",
                "description": "Test description",
                "uid": 456,
                "creator": "TestUser",
                "is_author": 1,
                "is_added": 1,
                "scope": "DEFAULT",
                "share_url": "https://example.com/kb/kb123",
                "extend_data": {
                    "get_note_count": 0,
                    "subscribe_count": 0,
                    "all_resource_count": 0,
                },
                "root_dir": {"id": 1},
                "create_time": 1609459200,
                "share_info": {"share_mode": "CLOSED"},
                "config": {"supported_file_type": []},
            },
        }
        mock_post.return_value = mock_response

        client = GetBijiClient(token="test_token")
        kb = client.knowledge.create(
            name="My Knowledge Base",
            description="Test description",
        )

        assert kb.id == 123
        assert kb.name == "My Knowledge Base"

    def test_create_knowledge_base_empty_name(self):
        """Test creating knowledge base with empty name raises ValidationError."""
        client = GetBijiClient(token="test_token")

        with pytest.raises(ValidationError) as exc_info:
            client.knowledge.create(name="")

        assert "cannot be empty" in str(exc_info.value).lower()

    @patch("getbiji_box.client.GetBijiClient.get")
    def test_list_mine(self, mock_get):
        """Test listing my knowledge bases."""
        mock_get.return_value = {
            "h": {"c": 0},
            "c": [
                {
                    "id": 1,
                    "id_alias": "kb1",
                    "name": "KB 1",
                    "uid": 100,
                    "creator": "User1",
                    "is_author": 1,
                    "share_url": "https://example.com/1",
                    "extend_data": {
                        "get_note_count": 5,
                        "subscribe_count": 0,
                        "all_resource_count": 5,
                    },
                    "root_dir": {"id": 10},
                    "create_time": 1609459200,
                },
                {
                    "id": 2,
                    "id_alias": "kb2",
                    "name": "KB 2",
                    "uid": 100,
                    "creator": "User1",
                    "is_author": 1,
                    "share_url": "https://example.com/2",
                    "extend_data": {
                        "get_note_count": 10,
                        "subscribe_count": 0,
                        "all_resource_count": 10,
                    },
                    "root_dir": {"id": 20},
                    "create_time": 1609459200,
                },
            ],
        }

        client = GetBijiClient(token="test_token")
        kbs = client.knowledge.list_mine()

        assert len(kbs) == 2
        assert kbs[0].name == "KB 1"
        assert kbs[1].name == "KB 2"

    @patch("getbiji_box.client.GetBijiClient.get")
    def test_get_detail(self, mock_get):
        """Test getting knowledge base details."""
        mock_get.return_value = {
            "h": {"c": 0},
            "c": {
                "id": 123,
                "id_alias": "test_alias",
                "name": "Test KB",
                "description": "Test Description",
                "uid": 456,
                "creator": "TestUser",
                "is_author": 1,
                "share_url": "https://example.com/kb/test_alias",
                "extend_data": {
                    "get_note_count": 100,
                    "subscribe_count": 50,
                    "all_resource_count": 150,
                },
                "root_dir": {"id": 1},
                "create_time": 1609459200,
                "share_info": {"share_mode": "CLOSED"},
                "config": {"supported_file_type": ["pdf", "docx"]},
            },
        }

        client = GetBijiClient(token="test_token")
        kb = client.knowledge.get_detail("test_alias")

        assert kb.id_alias == "test_alias"
        assert kb.name == "Test KB"
        assert kb.note_count == 100

    def test_get_detail_empty_id(self):
        """Test getting detail with empty ID raises ValidationError."""
        client = GetBijiClient(token="test_token")

        with pytest.raises(ValidationError) as exc_info:
            client.knowledge.get_detail("")

        assert "cannot be empty" in str(exc_info.value).lower()

    @patch("getbiji_box.client.GetBijiClient.get")
    def test_list_subscribed(self, mock_get):
        """Test listing subscribed knowledge bases."""
        mock_get.return_value = {
            "h": {"c": 0},
            "c": {
                "list": [
                    {
                        "id": 10,
                        "id_alias": "sub1",
                        "name": "Subscribed KB 1",
                        "uid": 200,
                        "creator": "OtherUser",
                        "is_author": 0,
                        "share_url": "https://example.com/sub1",
                        "extend_data": {
                            "get_note_count": 20,
                            "subscribe_count": 10,
                            "all_resource_count": 20,
                        },
                        "root_dir": {"id": 100},
                        "create_time": 1609459200,
                        "is_selection": 1,
                        "open_subscription": 1,
                        "share_info": {"share_mode": "OPEN"},
                    },
                ],
                "count": 1,
                "has_more": False,
            },
        }

        client = GetBijiClient(token="test_token")
        result = client.knowledge.list_subscribed(page=1, size=20)

        assert len(result.list) == 1
        assert result.count == 1
        assert result.has_more is False
        assert result.list[0].name == "Subscribed KB 1"

    @patch("getbiji_box.client.GetBijiClient.get")
    def test_get_note_in_knowledge_base(self, mock_get):
        """Test getting a note within a knowledge base."""
        mock_get.return_value = {
            "h": {"c": 0},
            "c": {
                "id": "note123",
                "title": "Note in KB",
                "content": "Content",
                "source": "knowledge",
                "is_in_topic": True,
                "topics": [
                    {
                        "topic_id": 456,
                        "topic_id_alias": "kb123",
                        "topic_name": "Test KB",
                    }
                ],
                "topic_id": "456",
                "tags": [],
                "attachments": [],
            },
        }

        client = GetBijiClient(token="test_token")
        note = client.knowledge.get_note("456", "note123")

        assert note.id == "note123"
        assert note.source == "knowledge"
        assert note.is_in_topic is True

    def test_get_note_empty_ids(self):
        """Test getting note with empty IDs raises ValidationError."""
        client = GetBijiClient(token="test_token")

        with pytest.raises(ValidationError):
            client.knowledge.get_note("", "note123")

        with pytest.raises(ValidationError):
            client.knowledge.get_note("456", "")

    @patch("getbiji_box.client.GetBijiClient.get")
    def test_list_resources(self, mock_get):
        """Test listing knowledge base resources."""
        mock_get.return_value = {
            "h": {"c": 0},
            "c": {
                "has_next": 1,
                "current_directory": {
                    "id": 120,
                    "topic_id": 35,
                    "parent_id": 0,
                    "name": "默认目录",
                    "type": "ROOT",
                },
                "directories": [
                    {
                        "id": 140,
                        "topic_id": 35,
                        "parent_id": 120,
                        "name": "子目录",
                        "type": "DEFAULT",
                    },
                ],
                "resources": [
                    {
                        "id": 52488057,
                        "uid": 1001534,
                        "topic_id": 2732516,
                        "topic_id_alias": "BJ8lRyAJ",
                        "directory_id": 120,
                        "resource_type": "NOTE",
                        "resource_note_meta_data": {"id": "123", "title": "Test"},
                        "create_time": 1769432041,
                    },
                ],
            },
        }

        client = GetBijiClient(token="test_token")
        result = client.knowledge.list_resources("BJ8lRyAJ", resource_type=2, page=1)

        assert result.has_next is True
        assert result.current_directory is not None
        assert len(result.directories) == 1
        assert len(result.resources) == 1
        assert result.resources[0].resource_type == "NOTE"

    def test_list_resources_empty_alias(self):
        """Test list_resources with empty alias raises ValidationError."""
        client = GetBijiClient(token="test_token")

        with pytest.raises(ValidationError):
            client.knowledge.list_resources("")

    @patch("getbiji_box.client.GetBijiClient.get")
    def test_list_featured(self, mock_get):
        """Test listing featured knowledge bases."""
        mock_get.return_value = {
            "h": {"c": 0},
            "c": {
                "list": [
                    {
                        "id": 35,
                        "id_alias": "lG0Prnaj",
                        "name": "罗振宇学习笔记",
                        "uid": 36043,
                        "creator": "罗振宇",
                        "is_author": 0,
                        "share_url": "https://biji.com/topic/lG0Prnaj",
                        "extend_data": {
                            "get_note_count": 515,
                            "subscribe_count": 748500,
                            "all_resource_count": 4075,
                        },
                        "root_dir": {"id": 120},
                        "is_selection": 1,
                        "open_subscription": 1,
                    },
                ],
                "count": 44,
                "has_more": True,
            },
        }

        client = GetBijiClient(token="test_token")
        result = client.knowledge.list_featured(page=1)

        assert len(result.list) == 1
        assert result.count == 44
        assert result.has_more is True
        assert result.list[0].name == "罗振宇学习笔记"

    @patch("getbiji_box.client.GetBijiClient.get")
    def test_list_managed(self, mock_get):
        """Test listing managed knowledge bases."""
        mock_get.return_value = {
            "h": {"c": 0},
            "c": {
                "list": [
                    {
                        "id": 1,
                        "id_alias": "kb1",
                        "name": "Managed KB",
                        "uid": 100,
                        "creator": "User1",
                        "is_author": 1,
                        "share_url": "https://example.com/1",
                        "extend_data": {
                            "get_note_count": 5,
                            "subscribe_count": 0,
                            "all_resource_count": 5,
                        },
                        "root_dir": {"id": 10},
                    },
                ],
                "count": 1,
                "has_more": False,
            },
        }

        client = GetBijiClient(token="test_token")
        result = client.knowledge.list_managed(page=1, size=50)

        assert len(result.list) == 1
        assert result.list[0].name == "Managed KB"

    @patch("getbiji_box.client.GetBijiClient.get")
    def test_list_follow_live_streams(self, mock_get):
        """Test listing live streams in a knowledge base."""
        mock_get.return_value = {
            "h": {"c": 0},
            "c": {
                "has_next": True,
                "list": [
                    {
                        "id": 100,
                        "uid": 36043,
                        "topic_id": 35,
                        "type": 2,
                        "name": "Test Live Stream",
                        "platform": "DEDAO",
                        "status": 2,
                        "ai_status": 2,
                    },
                ],
            },
        }

        client = GetBijiClient(token="test_token")
        result = client.knowledge.list_follow("lG0Prnaj", follow_type=2, page=1)

        assert result.has_next is True
        assert len(result.list) == 1
        assert result.list[0].name == "Test Live Stream"
        assert result.list[0].platform == "DEDAO"

    @patch("getbiji_box.client.GetBijiClient.get")
    def test_list_follow_bloggers(self, mock_get):
        """Test listing bloggers in a knowledge base."""
        mock_get.return_value = {
            "h": {"c": 0},
            "c": {
                "has_next": False,
                "list": [
                    {
                        "id": 200,
                        "uid": 36043,
                        "topic_id": 35,
                        "type": 1,
                        "name": "Test Blogger",
                    },
                ],
            },
        }

        client = GetBijiClient(token="test_token")
        result = client.knowledge.list_follow("lG0Prnaj", follow_type=1)

        assert result.has_next is False
        assert len(result.list) == 1
        assert result.list[0].type == 1

    def test_list_follow_empty_alias(self):
        """Test list_follow with empty alias raises ValidationError."""
        client = GetBijiClient(token="test_token")

        with pytest.raises(ValidationError):
            client.knowledge.list_follow("", follow_type=2)

    @patch("getbiji_box.client.GetBijiClient.post")
    def test_get_live_stream_detail(self, mock_post):
        """Test getting live stream post detail."""
        mock_response = Mock()
        mock_response.json.return_value = {
            "h": {"c": 0},
            "c": {
                "post_id": 123456,
                "post_id_str": "123456",
                "post_id_alias": "abc",
                "post_name": "Test Live",
                "post_type": 4,
                "post_cover": "",
                "post_title": "Test Title",
                "post_summary": "# AI Summary\nContent here",
                "post_cleaned_summary": "AI Summary\nContent here",
                "post_url": "https://dedao.cn/live/detail/123",
                "ai_status": 2,
            },
        }
        mock_post.return_value = mock_response

        client = GetBijiClient(token="test_token")
        post = client.knowledge.get_live_stream_detail("lG0Prnaj", "123456")

        assert post.post_id == 123456
        assert post.post_type == 4
        assert post.post_summary == "# AI Summary\nContent here"
        assert post.ai_status == 2

    def test_get_live_stream_detail_empty_params(self):
        """Test get_live_stream_detail with empty params raises ValidationError."""
        client = GetBijiClient(token="test_token")

        with pytest.raises(ValidationError):
            client.knowledge.get_live_stream_detail("", "123")

        with pytest.raises(ValidationError):
            client.knowledge.get_live_stream_detail("abc", "")

    @patch("getbiji_box.client.GetBijiClient.get")
    def test_list_notes_in_knowledge_base(self, mock_get):
        """Test listing notes within a knowledge base."""
        mock_get.return_value = {
            "h": {"c": 0},
            "c": {
                "list": [
                    {"id": "n1", "title": "Note 1", "content": "C1"},
                    {"id": "n2", "title": "Note 2", "content": "C2"},
                ],
                "total_items": 2,
                "has_more": False,
            },
        }

        client = GetBijiClient(token="test_token")
        result = client.knowledge.list_notes_in_knowledge_base(topic_id="35", limit=20)

        assert len(result.list) == 2
        assert result.list[0].title == "Note 1"
        assert result.has_more is False

    @patch("getbiji_box.client.GetBijiClient.get")
    def test_list_notes_in_knowledge_base_with_since_id(self, mock_get):
        """Test listing notes with pagination cursor."""
        mock_get.return_value = {
            "h": {"c": 0},
            "c": {"list": [], "total_items": 0, "has_more": False},
        }

        client = GetBijiClient(token="test_token")
        client.knowledge.list_notes_in_knowledge_base(topic_id="35", limit=10, since_id="abc")

        call_kwargs = mock_get.call_args
        assert "since_id" in call_kwargs.kwargs.get("params", {})

    def test_list_notes_in_knowledge_base_empty_id(self):
        """Test list_notes_in_knowledge_base with empty ID."""
        client = GetBijiClient(token="test_token")
        with pytest.raises(ValidationError):
            client.knowledge.list_notes_in_knowledge_base(topic_id="")

    @patch("getbiji_box.client.GetBijiClient.get")
    def test_get_by_share_url_topic(self, mock_get):
        """Test getting knowledge base by share URL with /topic/ pattern."""
        mock_get.return_value = {
            "h": {"c": 0},
            "c": {
                "id": 1,
                "id_alias": "abc123",
                "name": "Test",
                "uid": 1,
                "creator": "U",
                "is_author": 1,
                "share_url": "",
                "extend_data": {
                    "get_note_count": 0,
                    "subscribe_count": 0,
                    "all_resource_count": 0,
                },
                "root_dir": {"id": 1},
            },
        }

        client = GetBijiClient(token="test_token")
        kb = client.knowledge.get_by_share_url("https://getbiji.com/topic/abc123")
        assert kb.id_alias == "abc123"

    @patch("getbiji_box.client.GetBijiClient.get")
    def test_get_by_share_url_t_pattern(self, mock_get):
        """Test getting knowledge base by share URL with /t/ pattern."""
        mock_get.return_value = {
            "h": {"c": 0},
            "c": {
                "id": 1,
                "id_alias": "xyz",
                "name": "T",
                "uid": 1,
                "creator": "U",
                "is_author": 1,
                "share_url": "",
                "extend_data": {
                    "get_note_count": 0,
                    "subscribe_count": 0,
                    "all_resource_count": 0,
                },
                "root_dir": {"id": 1},
            },
        }

        client = GetBijiClient(token="test_token")
        kb = client.knowledge.get_by_share_url("https://getbiji.com/t/xyz")
        assert kb.id_alias == "xyz"

    def test_get_by_share_url_empty(self):
        """Test get_by_share_url with empty URL."""
        client = GetBijiClient(token="test_token")
        with pytest.raises(ValidationError):
            client.knowledge.get_by_share_url("")

    def test_get_by_share_url_invalid(self):
        """Test get_by_share_url with URL that has no extractable ID."""
        client = GetBijiClient(token="test_token")
        with pytest.raises(ValidationError, match="Could not extract"):
            client.knowledge.get_by_share_url("https://example.com/nothing")

    @patch("getbiji_box.client.GetBijiClient.get")
    def test_list_resources_with_directory_id(self, mock_get):
        """Test list_resources with directory_id parameter."""
        mock_get.return_value = {
            "h": {"c": 0},
            "c": {
                "has_next": 0,
                "current_directory": None,
                "directories": None,
                "resources": None,
            },
        }

        client = GetBijiClient(token="test_token")
        client.knowledge.list_resources("alias", resource_type=1, directory_id=120)

        call_kwargs = mock_get.call_args
        assert call_kwargs.kwargs["params"]["directory_id"] == 120

    @patch("getbiji_box.client.GetBijiClient.post")
    def test_get_follow_stat(self, mock_post):
        """Test getting follow statistics."""
        mock_response = Mock()
        mock_response.json.return_value = {
            "h": {"c": 0},
            "c": {
                "watching_count": 5,
                "max_watch_count": 20,
            },
        }
        mock_post.return_value = mock_response

        client = GetBijiClient(token="test_token")
        stat = client.knowledge.get_follow_stat()
        assert stat["watching_count"] == 5


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
