"""
Knowledge Base API for GetBiji.

Provides operations for managing knowledge bases (topics),
including creating, listing, and retrieving knowledge base details.
"""

from typing import TYPE_CHECKING, Any, Dict, List, Optional

from .exceptions import ValidationError
from .models import (
    FollowListResult,
    Knowledge,
    KnowledgeListResult,
    LiveStreamPost,
    Note,
    NoteListResult,
    ResourceListResult,
)

if TYPE_CHECKING:
    from .client import GetBijiClient


class KnowledgeAPI:
    """
    API for knowledge base (topic) operations.

    Knowledge bases are collections of notes organized by topic.
    They can be private or shared with others.
    """

    # API endpoints
    CREATE_URL = "https://knowledge-api.trytalks.com/v1/web/topic/create"
    LIST_MINE_URL = "https://knowledge-api.trytalks.com/v1/web/topic/mine/list"
    GET_DETAIL_URL = "https://knowledge-api.trytalks.com/v1/web/topic/detail"
    LIST_SUBSCRIBED_URL = "https://knowledge-api.trytalks.com/v1/web/subscribe/topic/list"
    GET_NOTE_URL = "https://get-notes.luojilab.com/voicenotes/web/topics/{}/notes/{}"
    LIST_FEATURED_URL = "https://knowledge-api.trytalks.com/v1/web/topic/list"
    LIST_MANAGED_URL = "https://knowledge-api.trytalks.com/v1/web/topic/list/manager"
    RESOURCE_LIST_URL = "https://knowledge-api.trytalks.com/v1/web/topic/resource/list/mix"
    FOLLOW_LIST_URL = "https://knowledge-api.trytalks.com/v1/web/follow/list"
    POST_DETAIL_URL = "https://knowledge-api.trytalks.com/v1/web/topic/post/detail"
    FOLLOW_STAT_URL = "https://knowledge-api.trytalks.com/v1/web/follow/watch/bloggers/stat"

    # Default headers for knowledge API
    DEFAULT_HEADERS = {
        "X-Appid": "3",
        "X-Av": "1.2.2",
    }

    def __init__(self, client: "GetBijiClient"):
        """
        Initialize KnowledgeAPI.

        Args:
            client: GetBijiClient instance
        """
        self._client = client

    def create(
        self,
        name: str,
        description: str = "",
    ) -> Knowledge:
        """
        Create a new knowledge base.

        Args:
            name: Knowledge base name (required)
            description: Description (optional)

        Returns:
            Created Knowledge object

        Raises:
            ValidationError: If name is empty
            APIError: If API returns an error

        Example:
            >>> kb = client.knowledge.create(
            ...     name="My Learning Notes",
            ...     description="Collection of my learning materials"
            ... )
            >>> print(f"Created: {kb.id_alias}")
        """
        if not name or not name.strip():
            raise ValidationError("Knowledge base name cannot be empty")

        payload = {
            "name": name.strip(),
        }

        if description:
            payload["description"] = description

        headers = dict(self.DEFAULT_HEADERS)

        response = self._client.post(
            self.CREATE_URL,
            json=payload,
            headers=headers,
        )
        data = self._client._parse_response(response)
        kb_data = data.get("c", {})

        return Knowledge.from_dict(kb_data)

    def list_mine(self) -> List[Knowledge]:
        """
        List knowledge bases created by the current user.

        Returns:
            List of Knowledge objects

        Raises:
            APIError: If API returns an error

        Example:
            >>> my_kbs = client.knowledge.list_mine()
            >>> for kb in my_kbs:
            ...     print(f"{kb.name}: {kb.note_count} notes")
        """
        headers = dict(self.DEFAULT_HEADERS)

        response = self._client.get(
            self.LIST_MINE_URL,
            headers=headers,
        )
        data = response.get("c", [])

        return [Knowledge.from_dict(kb_data) for kb_data in data if isinstance(kb_data, dict)]

    def get_detail(self, id_alias: str) -> Knowledge:
        """
        Get detailed information about a knowledge base.

        Args:
            id_alias: The knowledge base alias (can use id_alias or share ID)

        Returns:
            Knowledge object with full details

        Raises:
            ValidationError: If id_alias is empty
            APIError: If API returns an error

        Example:
            >>> kb = client.knowledge.get_detail("abc123")
            >>> print(f"{kb.name}")
            >>> print(f"Description: {kb.description}")
        """
        if not id_alias:
            raise ValidationError("Knowledge base ID cannot be empty")

        params = {
            "id_alias": id_alias,
            "source": "web",
        }

        headers = dict(self.DEFAULT_HEADERS)

        response = self._client.get(
            self.GET_DETAIL_URL,
            params=params,
            headers=headers,
        )
        data = response.get("c", {})

        return Knowledge.from_dict(data)

    def get_note(
        self,
        topic_id: str,
        note_id: str,
    ) -> Note:
        """
        Get a note within a knowledge base.

        Args:
            topic_id: The knowledge base ID
            note_id: The note ID

        Returns:
            Note object with knowledge base context

        Raises:
            ValidationError: If IDs are empty
            APIError: If API returns an error

        Example:
            >>> note = client.knowledge.get_note("456", "abc123")
            >>> print(f"{note.title}")
            >>> for topic in note.topics:
            ...     print(f"  in: {topic.get('topic_name')}")
        """
        if not topic_id or not note_id:
            raise ValidationError("Topic ID and Note ID are required")

        url = self.GET_NOTE_URL.format(topic_id, note_id)

        params = {
            "from": "GETNOTE",
        }

        response = self._client.get(url, params=params)
        data = response.get("c", {})

        return Note.from_dict(data)

    def list_subscribed(
        self,
        page: int = 1,
        size: int = 20,
    ) -> KnowledgeListResult:
        """
        List knowledge bases subscribed by the current user.

        Args:
            page: Page number (1-indexed, default: 1)
            size: Items per page (default: 20)

        Returns:
            KnowledgeListResult containing:
            - list: List of Knowledge objects
            - count: Total count
            - has_more: Whether there are more pages

        Raises:
            APIError: If API returns an error

        Example:
            >>> result = client.knowledge.list_subscribed(page=1, size=20)
            >>> for kb in result.list:
            ...     print(f"{kb.name} by {kb.creator}")
            >>>
            >>> if result.has_more:
            ...     next_page = client.knowledge.list_subscribed(page=2, size=20)
        """
        params = {
            "page": page,
            "size": size,
            "exclude_mine": "true",
        }

        headers = dict(self.DEFAULT_HEADERS)

        response = self._client.get(
            self.LIST_SUBSCRIBED_URL,
            params=params,
            headers=headers,
        )
        data = response.get("c", {})

        return KnowledgeListResult.from_dict(data)

    def list_notes_in_knowledge_base(
        self,
        topic_id: str,
        limit: int = 50,
        since_id: Optional[str] = None,
    ) -> NoteListResult:
        """
        List notes within a specific knowledge base.

        Uses the topic_id parameter to filter notes from the notes API.

        Args:
            topic_id: The knowledge base ID (as string)
            limit: Number of notes to retrieve (default: 50)
            since_id: Pagination cursor from previous call

        Returns:
            NoteListResult with notes from the knowledge base

        Raises:
            ValidationError: If topic_id is empty
            APIError: If API returns an error

        Example:
            >>> # Get first page of notes from knowledge base
            >>> result = client.knowledge.list_notes_in_knowledge_base(
            ...     topic_id="35",
            ...     limit=20
            ... )
            >>> for note in result.list:
            ...     print(f"{note.title}")
            >>>
            >>> # Get next page
            >>> if result.has_more:
            ...     next_result = client.knowledge.list_notes_in_knowledge_base(
            ...         topic_id="35",
            ...         limit=20,
            ...         since_id=result.list[-1].id
            ...     )
        """
        if not topic_id:
            raise ValidationError("Topic ID cannot be empty")

        # Use the notes list endpoint with topic_id filter
        params = {
            "limit": limit,
            "sort": "create_desc",
            "topic_id": topic_id,
        }

        if since_id:
            params["since_id"] = since_id

        response = self._client.get(
            self._client.NOTES_API_BASE + "/voicenotes/web/notes", params=params
        )
        data = response.get("c", {})

        # Parse notes from response
        notes_list = []
        for note_data in data.get("list", []):
            if isinstance(note_data, dict):
                notes_list.append(Note.from_dict(note_data))

        # Build result
        result = NoteListResult(
            list=notes_list,
            total_items=data.get("total_items", len(notes_list)),
            has_more=data.get("has_more", False),
            limit=limit,
        )

        return result

    def get_by_share_url(self, share_url: str) -> Knowledge:
        """
        Get a knowledge base by its share URL.

        This extracts the id_alias from the share URL and fetches details.

        Args:
            share_url: The full share URL (e.g., https://...)

        Returns:
            Knowledge object

        Raises:
            ValidationError: If URL is invalid
            APIError: If API returns an error

        Example:
            >>> kb = client.knowledge.get_by_share_url(
            ...     "https://getbiji.com/topic/abc123"
            ... )
        """
        if not share_url:
            raise ValidationError("Share URL cannot be empty")

        # Extract id_alias from URL
        # URL format: https://getbiji.com/topic/{id_alias}
        # or similar patterns
        import re

        patterns = [
            r"/topic/([a-zA-Z0-9_-]+)",
            r"/t/([a-zA-Z0-9_-]+)",
            r"id_alias[=:]([a-zA-Z0-9_-]+)",
        ]

        id_alias = None
        for pattern in patterns:
            match = re.search(pattern, share_url)
            if match:
                id_alias = match.group(1)
                break

        if not id_alias:
            raise ValidationError(f"Could not extract ID from share URL: {share_url}")

        return self.get_detail(id_alias)

    def list_resources(
        self,
        topic_id_alias: str,
        resource_type: int = 2,
        page: int = 1,
        sort: str = "create_time_desc",
        directory_id: Optional[int] = None,
    ) -> ResourceListResult:
        """
        List resources (notes + files) in a knowledge base.

        Args:
            topic_id_alias: Knowledge base alias
            resource_type: 1=files only (requires directory_id), 2=all resources
            page: Page number (1-indexed), fixed 20 items per page
            sort: Sort order (default: create_time_desc)
            directory_id: Directory ID (required when resource_type=1)

        Returns:
            ResourceListResult with has_next, directories, resources

        Raises:
            ValidationError: If topic_id_alias is empty
            APIError: If API returns an error
        """
        if not topic_id_alias:
            raise ValidationError("Knowledge base alias cannot be empty")

        params: Dict[str, Any] = {
            "topic_id": -1,
            "topic_id_alias": topic_id_alias,
            "resource_type": resource_type,
            "page": page,
            "sort": sort,
        }

        if directory_id is not None:
            params["directory_id"] = directory_id

        headers = dict(self.DEFAULT_HEADERS)

        response = self._client.get(
            self.RESOURCE_LIST_URL,
            params=params,
            headers=headers,
        )
        data = response.get("c", {})

        return ResourceListResult.from_dict(data)

    def list_featured(
        self,
        page: int = 1,
    ) -> KnowledgeListResult:
        """
        List featured/selected knowledge bases.

        Args:
            page: Page number (1-indexed, 20 items per page)

        Returns:
            KnowledgeListResult with featured knowledge bases
        """
        params: Dict[str, Any] = {
            "is_selection": 1,
            "page": page,
        }

        headers = dict(self.DEFAULT_HEADERS)

        response = self._client.get(
            self.LIST_FEATURED_URL,
            params=params,
            headers=headers,
        )
        data = response.get("c", {})

        return KnowledgeListResult.from_dict(data)

    def list_managed(
        self,
        page: int = 1,
        size: int = 50,
    ) -> KnowledgeListResult:
        """
        List managed knowledge bases (own + subscribed).

        Args:
            page: Page number (1-indexed)
            size: Items per page (default: 50)

        Returns:
            KnowledgeListResult with managed knowledge bases
        """
        params: Dict[str, Any] = {
            "is_selection": 0,
            "page": page,
            "size": size,
        }

        headers = dict(self.DEFAULT_HEADERS)

        response = self._client.get(
            self.LIST_MANAGED_URL,
            params=params,
            headers=headers,
        )
        data = response.get("c", {})

        return KnowledgeListResult.from_dict(data)

    def list_follow(
        self,
        topic_id_alias: str,
        follow_type: int,
        page: int = 1,
        page_size: int = 20,
    ) -> FollowListResult:
        """
        List follow items (live streams or bloggers) in a knowledge base.

        Args:
            topic_id_alias: Knowledge base alias
            follow_type: 1=bloggers, 2=live streams
            page: Page number (1-indexed)
            page_size: Items per page (default: 20)

        Returns:
            FollowListResult with follow items

        Raises:
            ValidationError: If topic_id_alias is empty
        """
        if not topic_id_alias:
            raise ValidationError("Knowledge base alias cannot be empty")

        params: Dict[str, Any] = {
            "topic_id": -1,
            "topic_id_alias": topic_id_alias,
            "type": follow_type,
            "page": page,
            "page_size": page_size,
        }

        headers = dict(self.DEFAULT_HEADERS)

        response = self._client.get(
            self.FOLLOW_LIST_URL,
            params=params,
            headers=headers,
        )
        data = response.get("c", {})

        return FollowListResult.from_dict(data)

    def get_live_stream_detail(
        self,
        topic_id_alias: str,
        post_id: str,
    ) -> LiveStreamPost:
        """
        Get live stream post detail.

        Args:
            topic_id_alias: Knowledge base alias
            post_id: The post ID (from follow list)

        Returns:
            LiveStreamPost with summary content

        Raises:
            ValidationError: If parameters are empty
        """
        if not topic_id_alias or not post_id:
            raise ValidationError("Knowledge base alias and post ID are required")

        payload = {
            "topic_id": -1,
            "topic_id_alias": topic_id_alias,
            "post_id": post_id,
        }

        headers = dict(self.DEFAULT_HEADERS)

        response = self._client.post(
            self.POST_DETAIL_URL,
            json=payload,
            headers=headers,
        )
        data = self._client._parse_response(response)

        return LiveStreamPost.from_dict(data.get("c", {}))

    def get_follow_stat(self) -> Dict[str, Any]:
        """
        Get follow/subscription statistics.

        Returns:
            Dict with watching_stat_desc, watching_count, max_watch_count, etc.
        """
        payload = {"followee_type": 1}
        headers = dict(self.DEFAULT_HEADERS)

        response = self._client.post(
            self.FOLLOW_STAT_URL,
            json=payload,
            headers=headers,
        )
        data = self._client._parse_response(response)

        return data.get("c", {})
