"""Managers for workflow entities.

These managers provide convenience methods for working with workflow
entities through the client.plugin_manager() interface.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
    from better_notion._sdk.client import NotionClient


class OrganizationManager:
    """
    Manager for Organization entities.

    Provides convenience methods for working with organizations.

    Example:
        >>> manager = client.plugin_manager("organizations")
        >>> orgs = await manager.list()
        >>> org = await manager.get("org_id")
    """

    def __init__(self, client: "NotionClient") -> None:
        """Initialize organization manager.

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

    async def list(self) -> list:
        """
        List all organizations.

        Returns:
            List of Organization instances
        """
        from better_notion.plugins.official.agents_sdk.models import Organization

        # Get database ID from workspace config
        database_id = self._get_database_id("Organizations")
        if not database_id:
            return []

        # Query all pages
        response = await self._client._api.databases.query(database_id=database_id)

        return [
            Organization(self._client, page_data)
            for page_data in response.get("results", [])
        ]

    async def get(self, org_id: str) -> Any:
        """
        Get an organization by ID.

        Args:
            org_id: Organization page ID

        Returns:
            Organization instance
        """
        from better_notion.plugins.official.agents_sdk.models import Organization

        return await Organization.get(org_id, client=self._client)

    async def create(
        self,
        name: str,
        slug: str | None = None,
        description: str | None = None,
        repository_url: str | None = None,
        status: str = "Active",
    ) -> Any:
        """
        Create a new organization.

        Args:
            name: Organization name
            slug: URL-safe identifier
            description: Organization description
            repository_url: Code repository URL
            status: Organization status

        Returns:
            Created Organization instance
        """
        from better_notion.plugins.official.agents_sdk.models import Organization

        database_id = self._get_database_id("Organizations")
        if not database_id:
            raise ValueError("Organizations database ID not found in workspace config")

        return await Organization.create(
            client=self._client,
            database_id=database_id,
            name=name,
            slug=slug,
            description=description,
            repository_url=repository_url,
            status=status,
        )

    def _get_database_id(self, name: str) -> str | None:
        """Get database ID from workspace config."""
        return getattr(self._client, "_workspace_config", {}).get(name)


class ProjectManager:
    """
    Manager for Project entities.

    Example:
        >>> manager = client.plugin_manager("projects")
        >>> projects = await manager.list()
        >>> project = await manager.get("project_id")
    """

    def __init__(self, client: "NotionClient") -> None:
        """Initialize project manager."""
        self._client = client

    async def list(self, organization_id: str | None = None) -> list:
        """
        List all projects, optionally filtered by organization.

        Args:
            organization_id: Filter by organization ID (optional)

        Returns:
            List of Project instances
        """
        from better_notion.plugins.official.agents_sdk.models import Project

        database_id = self._get_database_id("Projects")
        if not database_id:
            return []

        # Build filter
        filter_dict: dict[str, Any] = {}
        if organization_id:
            filter_dict = {
                "property": "Organization",
                "relation": {"contains": organization_id},
            }

        # Query pages
        response = await self._client._api.databases.query(
            database_id=database_id,
            filter=filter_dict if filter_dict else None,
        )

        return [
            Project(self._client, page_data)
            for page_data in response.get("results", [])
        ]

    async def get(self, project_id: str) -> Any:
        """Get a project by ID."""
        from better_notion.plugins.official.agents_sdk.models import Project

        return await Project.get(project_id, client=self._client)

    async def create(
        self,
        name: str,
        organization_id: str,
        slug: str | None = None,
        description: str | None = None,
        repository: str | None = None,
        status: str = "Active",
        tech_stack: list[str] | None = None,
        role: str = "Developer",
    ) -> Any:
        """Create a new project."""
        from better_notion.plugins.official.agents_sdk.models import Project

        database_id = self._get_database_id("Projects")
        if not database_id:
            raise ValueError("Projects database ID not found in workspace config")

        return await Project.create(
            client=self._client,
            database_id=database_id,
            name=name,
            organization_id=organization_id,
            slug=slug,
            description=description,
            repository=repository,
            status=status,
            tech_stack=tech_stack,
            role=role,
        )

    def _get_database_id(self, name: str) -> str | None:
        """Get database ID from workspace config."""
        return getattr(self._client, "_workspace_config", {}).get(name)


class VersionManager:
    """
    Manager for Version entities.

    Example:
        >>> manager = client.plugin_manager("versions")
        >>> versions = await manager.list()
        >>> version = await manager.get("version_id")
    """

    def __init__(self, client: "NotionClient") -> None:
        """Initialize version manager."""
        self._client = client

    async def list(self, project_id: str | None = None) -> list:
        """
        List all versions, optionally filtered by project.

        Args:
            project_id: Filter by project ID (optional)

        Returns:
            List of Version instances
        """
        from better_notion.plugins.official.agents_sdk.models import Version

        database_id = self._get_database_id("Versions")
        if not database_id:
            return []

        # Build filter
        filter_dict: dict[str, Any] = {}
        if project_id:
            filter_dict = {
                "property": "Project",
                "relation": {"contains": project_id},
            }

        # Query pages
        response = await self._client._api.databases.query(
            database_id=database_id,
            filter=filter_dict if filter_dict else None,
        )

        return [
            Version(self._client, page_data)
            for page_data in response.get("results", [])
        ]

    async def get(self, version_id: str) -> Any:
        """Get a version by ID."""
        from better_notion.plugins.official.agents_sdk.models import Version

        return await Version.get(version_id, client=self._client)

    async def create(
        self,
        name: str,
        project_id: str,
        status: str = "Planning",
        version_type: str = "Minor",
        branch_name: str | None = None,
        progress: int = 0,
    ) -> Any:
        """Create a new version."""
        from better_notion.plugins.official.agents_sdk.models import Version

        database_id = self._get_database_id("Versions")
        if not database_id:
            raise ValueError("Versions database ID not found in workspace config")

        return await Version.create(
            client=self._client,
            database_id=database_id,
            name=name,
            project_id=project_id,
            status=status,
            version_type=version_type,
            branch_name=branch_name,
            progress=progress,
        )

    def _get_database_id(self, name: str) -> str | None:
        """Get database ID from workspace config."""
        return getattr(self._client, "_workspace_config", {}).get(name)


class TaskManager:
    """
    Manager for Task entities.

    Provides task discovery and workflow management methods.

    Example:
        >>> manager = client.plugin_manager("tasks")
        >>> tasks = await manager.list()
        >>> task = await manager.next()
        >>> await task.claim()
    """

    def __init__(self, client: "NotionClient") -> None:
        """Initialize task manager."""
        self._client = client

    async def list(
        self,
        version_id: str | None = None,
        status: str | None = None,
    ) -> list:
        """
        List all tasks, optionally filtered.

        Args:
            version_id: Filter by version ID (optional)
            status: Filter by status (optional)

        Returns:
            List of Task instances
        """
        from better_notion.plugins.official.agents_sdk.models import Task

        database_id = self._get_database_id("Tasks")
        if not database_id:
            return []

        # Build filter
        filters: list[dict[str, Any]] = []

        if version_id:
            filters.append({
                "property": "Version",
                "relation": {"contains": version_id},
            })

        if status:
            filters.append({
                "property": "Status",
                "select": {"equals": status},
            })

        # Build query payload
        query_payload = {}
        if filters:
            # Apply filter only if there are filters
            if len(filters) == 1:
                query_payload["filter"] = filters[0]
            else:
                query_payload["filter"] = {"and": filters}

        # Query pages
        response = await self._client._api.databases.query(
            database_id=database_id,
            **query_payload
        )

        return [
            Task(self._client, page_data)
            for page_data in response.get("results", [])
        ]

    async def get(self, task_id: str) -> Any:
        """Get a task by ID."""
        from better_notion.plugins.official.agents_sdk.models import Task

        return await Task.get(task_id, client=self._client)

    async def create(
        self,
        title: str,
        version_id: str,
        status: str = "Backlog",
        task_type: str = "New Feature",
        priority: str = "Medium",
        dependency_ids: list[str] | None = None,
        estimated_hours: int | None = None,
    ) -> Any:
        """Create a new task."""
        from better_notion.plugins.official.agents_sdk.models import Task

        database_id = self._get_database_id("Tasks")
        if not database_id:
            raise ValueError("Tasks database ID not found in workspace config")

        return await Task.create(
            client=self._client,
            database_id=database_id,
            title=title,
            version_id=version_id,
            status=status,
            task_type=task_type,
            priority=priority,
            dependency_ids=dependency_ids,
            estimated_hours=estimated_hours,
        )

    async def next(self, project_id: str | None = None) -> Any | None:
        """
        Find the next available task to work on.

        Tasks are considered available if:
        - Status is Backlog or Claimed
        - All dependencies are completed

        Args:
            project_id: Filter by project ID (optional)

        Returns:
            Task instance or None if no tasks available

        Raises:
            ValueError: If project_id is provided but project doesn't exist
        """
        from better_notion.plugins.official.agents_sdk.models import Task, Project

        database_id = self._get_database_id("Tasks")
        if not database_id:
            return None

        # Validate project_id if provided
        if project_id:
            # First check if Projects database exists in workspace config
            projects_db = self._get_database_id("Projects")
            if not projects_db:
                # Workspace not initialized, can't validate project
                pass
            else:
                # Check if project exists by querying for it
                try:
                    project_response = await self._client._api.databases.query(
                        database_id=projects_db,
                        filter={"property": "id", "rich_text": {"equals": project_id}}
                    )
                    # If no results, project doesn't exist
                    if not project_response.get("results"):
                        raise ValueError(
                            f"Project '{project_id}' not found. "
                            f"Please verify the project ID or run 'notion agents projects list' to see available projects."
                        )
                except Exception as e:
                    if "not found" in str(e).lower():
                        raise
                    # If query fails for other reasons, continue without validation

        # Filter for backlog/claimed tasks
        response = await self._client._api.databases.query(
            database_id=database_id,
            filter={
                "or": [
                    {"property": "Status", "select": {"equals": "Backlog"}},
                    {"property": "Status", "select": {"equals": "Claimed"}},
                ]
            },
        )

        # Check each task for completed dependencies
        for page_data in response.get("results", []):
            task = Task(self._client, page_data)

            # Filter by project if specified
            if project_id:
                version = await task.version()
                if version:
                    project = await version.project()
                    if project and project.id != project_id:
                        continue

            # Check if can start
            if await task.can_start():
                return task

        return None

    async def find_ready(self, version_id: str | None = None) -> list:
        """
        Find all tasks that are ready to start (dependencies completed).

        Args:
            version_id: Filter by version ID (optional)

        Returns:
            List of Task instances ready to start
        """
        ready_tasks = []

        database_id = self._get_database_id("Tasks")
        if not database_id:
            return ready_tasks

        # Get all backlog/claimed tasks
        tasks = await self.list(status=None)

        for task in tasks:
            # Filter by version if specified
            if version_id and task.version_id != version_id:
                continue

            # Check status and dependencies
            if task.status in ("Backlog", "Claimed") and await task.can_start():
                ready_tasks.append(task)

        return ready_tasks

    async def find_blocked(self, version_id: str | None = None) -> list:
        """
        Find all tasks that are blocked by incomplete dependencies.

        Args:
            version_id: Filter by version ID (optional)

        Returns:
            List of Task instances that are blocked
        """
        blocked_tasks = []

        database_id = self._get_database_id("Tasks")
        if not database_id:
            return blocked_tasks

        # Get all backlog/claimed/in-progress tasks
        tasks = await self.list(status=None)

        for task in tasks:
            # Filter by version if specified
            if version_id and task.version_id != version_id:
                continue

            # Check status and dependencies
            if task.status in ("Backlog", "Claimed", "In Progress"):
                if not await task.can_start():
                    blocked_tasks.append(task)

        return blocked_tasks

    async def assign(self, task_id: str, assignee: str) -> dict:
        """
        Assign a task to a person.

        Args:
            task_id: Task ID to assign
            assignee: Name of the person to assign to

        Returns:
            Dict with task_id, assigned_to, and previous assignee

        Example:
            >>> result = await manager.assign("task_123", "Alice Chen")
        """
        from better_notion.plugins.official.agents_sdk.models import Task

        task = await Task.get(task_id, client=self._client)
        previous = task.assignee

        await task.assign_to(assignee)

        return {
            "task_id": task_id,
            "assigned_to": assignee,
            "previous": previous
        }

    async def unassign(self, task_id: str) -> dict:
        """
        Unassign a task.

        Args:
            task_id: Task ID to unassign

        Returns:
            Dict with task_id, assigned_to (None), and previous assignee

        Example:
            >>> result = await manager.unassign("task_123")
        """
        from better_notion.plugins.official.agents_sdk.models import Task

        task = await Task.get(task_id, client=self._client)
        previous = task.assignee

        await task.unassign()

        return {
            "task_id": task_id,
            "assigned_to": None,
            "previous": previous
        }

    async def reassign(self, task_id: str, from_assignee: str, to_assignee: str) -> dict:
        """
        Reassign a task from one person to another.

        Args:
            task_id: Task ID to reassign
            from_assignee: Current assignee (for validation)
            to_assignee: New assignee

        Returns:
            Dict with task_id, from, and to

        Raises:
            ValueError: If task is not assigned to from_assignee

        Example:
            >>> result = await manager.reassign("task_123", "Alice", "Bob")
        """
        from better_notion.plugins.official.agents_sdk.models import Task

        task = await Task.get(task_id, client=self._client)

        if task.assignee != from_assignee:
            raise ValueError(f"Task is not assigned to {from_assignee}")

        await task.assign_to(to_assignee)

        return {
            "task_id": task_id,
            "from": from_assignee,
            "to": to_assignee
        }

    async def list_by_assignee(
        self,
        assignee: str,
        status: str | None = None
    ) -> list:
        """
        List tasks assigned to a person.

        Args:
            assignee: Name of the assignee
            status: Optional status filter

        Returns:
            List of Task instances

        Example:
            >>> tasks = await manager.list_by_assignee("Alice Chen", status="In Progress")
        """
        from better_notion.plugins.official.agents_sdk.models import Task

        database_id = self._get_database_id("Tasks")
        if not database_id:
            return []

        filters: list[dict[str, Any]] = [
            {
                "property": "Assignee",
                "select": {"equals": assignee}
            }
        ]

        if status:
            filters.append({
                "property": "Status",
                "select": {"equals": status}
            })

        response = await self._client._api.databases.query(
            database_id=database_id,
            filter={"and": filters} if len(filters) > 1 else filters[0]
        )

        return [
            Task(self._client, page_data)
            for page_data in response.get("results", [])
        ]

    async def list_unassigned(self) -> list:
        """
        List unassigned tasks.

        Returns:
            List of Task instances with no assignee

        Example:
            >>> tasks = await manager.list_unassigned()
        """
        from better_notion.plugins.official.agents_sdk.models import Task

        database_id = self._get_database_id("Tasks")
        if not database_id:
            return []

        response = await self._client._api.databases.query(
            database_id=database_id,
            filter={
                "property": "Assignee",
                "select": {"is_empty": True}
            }
        )

        return [
            Task(self._client, page_data)
            for page_data in response.get("results", [])
        ]

    async def can_start(self, task_id: str) -> dict:
        """
        Check if a task can start (all dependencies completed).

        Args:
            task_id: Task ID to check

        Returns:
            Dict with can_start (bool), task_id, and incomplete_dependencies

        Example:
            >>> result = await manager.can_start("task_123")
        """
        from better_notion.plugins.official.agents_sdk.models import Task

        task = await Task.get(task_id, client=self._client)
        deps = await task.dependencies()
        incomplete = [d for d in deps if d.status != "Completed"]

        return {
            "can_start": len(incomplete) == 0,
            "task_id": task_id,
            "incomplete_dependencies": [
                {"id": d.id, "title": d.title, "status": d.status}
                for d in incomplete
            ]
        }

    async def deps(self, task_id: str) -> dict:
        """
        List all dependencies of a task.

        Args:
            task_id: Task ID

        Returns:
            Dict with task_id and dependencies list

        Example:
            >>> result = await manager.deps("task_123")
        """
        from better_notion.plugins.official.agents_sdk.models import Task

        task = await Task.get(task_id, client=self._client)
        deps = await task.dependencies()

        return {
            "task_id": task_id,
            "dependencies": [
                {
                    "id": d.id,
                    "title": d.title,
                    "status": d.status
                }
                for d in deps
            ]
        }

    async def ready(self, version_id: str | None = None) -> list:
        """
        List all tasks ready to start (dependencies completed).

        Args:
            version_id: Optional version filter

        Returns:
            List of Task instances ready to start

        Example:
            >>> tasks = await manager.ready(version_id="ver_123")
        """
        return await self.find_ready(version_id)

    async def search(
        self,
        query: str,
        status: str | None = None,
        priority: str | None = None,
        assignee: str | None = None,
        project_id: str | None = None,
        version_id: str | None = None,
        limit: int = 50,
    ) -> list[dict]:
        """Search tasks by text query with optional filters.

        Args:
            query: Text search query
            status: Optional status filter
            priority: Optional priority filter
            assignee: Optional assignee filter
            project_id: Optional project ID filter
            version_id: Optional version ID filter
            limit: Maximum results to return

        Returns:
            List of search result dictionaries
        """
        from better_notion.plugins.official.agents_sdk.search import TextSearcher

        database_id = self._get_database_id("Tasks")
        if not database_id:
            return []

        # Build filters
        filters: list[dict[str, Any]] = []

        if status:
            filters.append({"property": "Status", "select": {"equals": status}})

        if priority:
            filters.append({"property": "Priority", "select": {"equals": priority}})

        if assignee:
            filters.append({"property": "Assignee", "select": {"equals": assignee}})

        # Combine filters
        filter_dict = None
        if filters:
            if len(filters) == 1:
                filter_dict = filters[0]
            else:
                filter_dict = {"and": filters}

        searcher = TextSearcher(self._client)
        results = await searcher.search_tasks(query, database_id, filter_dict, limit)

        # Filter by project/version if specified (post-filter due to relation filtering)
        if project_id or version_id:
            filtered_results = []
            for result in results:
                task = result.entity
                # Filter by version
                if version_id:
                    task_version = getattr(task, "version_id", None)
                    if task_version != version_id:
                        continue

                # Filter by project
                if project_id:
                    version = await task.version() if hasattr(task, "version") else None
                    if version:
                        project = await version.project() if hasattr(version, "project") else None
                        if project and project.id != project_id:
                            continue

                filtered_results.append(result)

            results = filtered_results

        return [r.to_dict() for r in results]

    async def pick(
        self,
        skills: list[str] | None = None,
        max_priority: str | None = None,
        exclude_patterns: list[str] | None = None,
        count: int = 5,
        project_id: str | None = None,
        version_id: str | None = None,
    ) -> list[dict]:
        """Pick the best tasks for an agent to work on.

        Args:
            skills: List of agent skills (e.g., ["python", "database"])
            max_priority: Maximum priority to consider
            exclude_patterns: Regex patterns to exclude
            count: Maximum number of recommendations
            project_id: Optional project filter
            version_id: Optional version filter

        Returns:
            List of task recommendation dictionaries
        """
        from better_notion.plugins.official.agents_sdk.agent import TaskSelector

        selector = TaskSelector(self._client)
        recommendations = await selector.pick_best_tasks(
            skills=skills,
            max_priority=max_priority,
            exclude_patterns=exclude_patterns,
            count=count,
            project_id=project_id,
            version_id=version_id,
        )

        return [r.to_dict() for r in recommendations]

    async def suggest(
        self,
        unassigned: bool = False,
        priority: list[str] | None = None,
        count: int = 5,
    ) -> list[dict]:
        """Suggest tasks based on criteria.

        Args:
            unassigned: Only suggest unassigned tasks
            priority: List of priority levels to include
            count: Maximum number of suggestions

        Returns:
            List of task dictionaries
        """
        # Get candidate tasks
        filters = []

        if unassigned:
            filters.append({"property": "Assignee", "select": {"is_empty": True}})

        if priority:
            or_filter = {"or": [{"property": "Priority", "select": {"equals": p}} for p in priority]}
            filters.append(or_filter)

        # Query with filters
        database_id = self._get_database_id("Tasks")
        if not database_id:
            return []

        query_obj: dict[str, Any] = {}
        if filters:
            if len(filters) == 1:
                query_obj["filter"] = filters[0]
            else:
                query_obj["filter"] = {"and": filters}

        from better_notion.plugins.official.agents_sdk.models import Task

        response = await self._client._api._request(
            "POST",
            f"/databases/{database_id}/query",
            json=query_obj,
        )

        tasks = [Task(self._client, page_data) for page_data in response.get("results", [])]

        # Sort by priority (Critical > High > Medium > Low)
        priority_order = {"Critical": 0, "High": 1, "Medium": 2, "Low": 3}
        tasks.sort(key=lambda t: priority_order.get(getattr(t, "priority", "Low"), 3))

        # Get top N and convert to dicts
        suggestions = []
        for task in tasks[:count]:
            suggestions.append({
                "id": task.id,
                "title": task.title,
                "priority": getattr(task, "priority", None),
                "status": getattr(task, "status", None),
                "assignee": getattr(task, "assignee", None),
                "type": getattr(task, "task_type", None),
            })

        return suggestions

    async def claim(self, task_id: str) -> dict:
        """Claim a task (set status to In Progress).

        Args:
            task_id: Task ID to claim

        Returns:
            Dict with task_id and new status
        """
        from better_notion.plugins.official.agents_sdk.models import Task

        task = await Task.get(task_id, client=self._client)
        await task.update(status="In Progress")

        return {
            "task_id": task_id,
            "status": "In Progress",
        }

    async def start(self, task_id: str) -> dict:
        """Start a task (alias for claim).

        Args:
            task_id: Task ID to start

        Returns:
            Dict with task_id and new status
        """
        return await self.claim(task_id)

    async def complete(self, task_id: str) -> dict:
        """Complete a task (set status to Completed).

        Args:
            task_id: Task ID to complete

        Returns:
            Dict with task_id and new status
        """
        from better_notion.plugins.official.agents_sdk.models import Task

        task = await Task.get(task_id, client=self._client)
        await task.update(status="Completed")

        return {
            "task_id": task_id,
            "status": "Completed",
        }

    def _get_database_id(self, name: str) -> str | None:
        """Get database ID from workspace config."""
        return getattr(self._client, "_workspace_config", {}).get(name)


class IdeaManager:
    """
    Manager for Idea entities.

    Provides convenience methods for working with Ideas,
    including filtering by project, category, and status.
    """

    def __init__(self, client: "NotionClient") -> None:
        """Initialize manager with NotionClient instance."""
        self._client = client

    async def list(
        self,
        project_id: str | None = None,
        category: str | None = None,
        status: str | None = None,
        effort_estimate: str | None = None,
    ) -> list:
        """
        List Ideas with optional filtering.

        Args:
            project_id: Filter by project ID
            category: Filter by category (enhancement, feature, bugfix, optimization, research)
            status: Filter by status
            effort_estimate: Filter by effort estimate

        Returns:
            List of Idea instances
        """
        from better_notion.plugins.official.agents_sdk.models import Idea

        database_id = self._get_database_id("Ideas")
        if not database_id:
            return []

        # Build filters
        filters = []

        if project_id:
            filters.append({
                "property": "Project",
                "relation": {"contains": project_id}
            })

        if category:
            filters.append({
                "property": "Category",
                "select": {"equals": category}
            })

        if status:
            filters.append({
                "property": "Status",
                "select": {"equals": status}
            })

        if effort_estimate:
            filters.append({
                "property": "Effort Estimate",
                "select": {"equals": effort_estimate}
            })

        # Query database
        query = {}
        if filters:
            if len(filters) == 1:
                query["filter"] = filters[0]
            else:
                query["filter"] = {
                    "and": filters
                }

        response = await self._client._api._request(
            "POST",
            f"/databases/{database_id}/query",
            json=query,
        )

        # Create Idea instances
        ideas = []
        for page_data in response.get("results", []):
            idea = Idea(self._client, page_data)
            ideas.append(idea)

        return ideas

    async def review_batch(self, count: int = 10) -> list:
        """
        Get a batch of ideas for review, prioritized by effort.

        Args:
            count: Maximum number of ideas to return

        Returns:
            List of Idea instances ready for review
        """
        ideas = await self.list(status="Proposed")

        # Sort by effort (XS < S < M < L < XL)
        effort_order = {"XS": 0, "S": 1, "M": 2, "L": 3, "XL": 4}
        ideas.sort(key=lambda i: effort_order.get(i.effort_estimate or "M", 2))

        return ideas[:count]

    async def get_accepted_without_tasks(self) -> list:
        """
        Get all accepted ideas that don't have related tasks yet.

        Returns:
            List of Idea instances that should have tasks created
        """
        ideas = await self.list(status="Accepted")
        return [idea for idea in ideas if not idea.related_task_id]

    async def search(
        self,
        query: str,
        status: str | None = None,
        category: str | None = None,
        project_id: str | None = None,
        limit: int = 50,
    ) -> list[dict]:
        """Search ideas by text query with optional filters.

        Args:
            query: Text search query
            status: Optional status filter
            category: Optional category filter
            project_id: Optional project ID filter
            limit: Maximum results to return

        Returns:
            List of search result dictionaries
        """
        from better_notion.plugins.official.agents_sdk.search import TextSearcher

        database_id = self._get_database_id("Ideas")
        if not database_id:
            return []

        # Build filters
        filters: list[dict[str, Any]] = []

        if status:
            filters.append({"property": "Status", "select": {"equals": status}})

        if category:
            filters.append({"property": "Category", "select": {"equals": category}})

        if project_id:
            filters.append({"property": "Project", "relation": {"contains": project_id}})

        # Combine filters
        filter_dict = None
        if filters:
            if len(filters) == 1:
                filter_dict = filters[0]
            else:
                filter_dict = {"and": filters}

        searcher = TextSearcher(self._client)
        results = await searcher.search_ideas(query, database_id, filter_dict, limit)

        return [r.to_dict() for r in results]

    def _get_database_id(self, name: str) -> str | None:
        """Get database ID from workspace config."""
        return getattr(self._client, "_workspace_config", {}).get(name)


class WorkIssueManager:
    """
    Manager for Work Issue entities.

    Provides convenience methods for working with work issues,
    including finding blockers and creating from exceptions.
    """

    def __init__(self, client: "NotionClient") -> None:
        """Initialize manager with NotionClient instance."""
        self._client = client

    async def list(
        self,
        project_id: str | None = None,
        task_id: str | None = None,
        type_: str | None = None,
        severity: str | None = None,
        status: str | None = None,
    ) -> list:
        """
        List Work Issues with optional filtering.

        Args:
            project_id: Filter by project ID
            task_id: Filter by task ID
            type_: Filter by type
            severity: Filter by severity
            status: Filter by status

        Returns:
            List of WorkIssue instances
        """
        from better_notion.plugins.official.agents_sdk.models import WorkIssue

        database_id = self._get_database_id("Work_issues")
        if not database_id:
            return []

        # Build filters
        filters = []

        if project_id:
            filters.append({
                "property": "Project",
                "relation": {"contains": project_id}
            })

        if task_id:
            filters.append({
                "property": "Task",
                "relation": {"contains": task_id}
            })

        if type_:
            filters.append({
                "property": "Type",
                "select": {"equals": type_}
            })

        if severity:
            filters.append({
                "property": "Severity",
                "select": {"equals": severity}
            })

        if status:
            filters.append({
                "property": "Status",
                "select": {"equals": status}
            })

        # Query database
        query = {}
        if filters:
            if len(filters) == 1:
                query["filter"] = filters[0]
            else:
                query["filter"] = {
                    "and": filters
                }

        response = await self._client._api._request(
            "POST",
            f"/databases/{database_id}/query",
            json=query,
        )

        # Create WorkIssue instances
        issues = []
        for page_data in response.get("results", []):
            issue = WorkIssue(self._client, page_data)
            issues.append(issue)

        return issues

    async def find_blockers(self, project_id: str) -> list:
        """
        Find all open work issues that are blocking development.

        Args:
            project_id: Project ID to search within

        Returns:
            List of WorkIssue instances with High/Critical severity
        """
        issues = await self.list(
            project_id=project_id,
            status="Open"
        )

        return [issue for issue in issues if issue.severity in ("High", "Critical")]

    async def create_from_exception(
        self,
        title: str,
        exception: Exception,
        project_id: str,
        task_id: str | None = None,
        context: str | None = None,
    ) -> "WorkIssue":
        """
        Create a work issue from an exception.

        Args:
            title: Issue title
            exception: Exception object
            project_id: Project ID
            task_id: Related task ID (optional)
            context: Additional context

        Returns:
            Created WorkIssue instance
        """
        from better_notion.plugins.official.agents_sdk.models import WorkIssue

        database_id = self._get_database_id("Work_issues")
        if not database_id:
            raise ValueError("Work Issues database not configured")

        # Create issue in Notion
        properties = {
            "title": {"title": [{"text": {"content": title}}]},
            "project_id": {"relation": [{"id": project_id}]},
            "type": {"select": {"name": "Technical"}},
            "severity": {"select": {"name": "Medium"}},
            "status": {"select": {"name": "Open"}},
            "description": {
                "rich_text": [{
                    "text": {
                        "content": f"Exception: {type(exception).__name__}: {str(exception)}"
                    }
                }]
            },
        }

        if task_id:
            properties["task_id"] = {"relation": [{"id": task_id}]}

        if context:
            properties["context"] = {
                "rich_text": [{"text": {"content": context}}]
            }

        response = await self._client._api._request(
            "POST",
            f"/databases/{database_id}",
            json={"properties": properties},
        )

        # Create WorkIssue instance
        issue = WorkIssue(self._client, response)

        return issue

    async def list_blocked_by(self, work_issue_id: str) -> list:
        """
        List tasks blocked by a work issue.

        Args:
            work_issue_id: Work issue ID

        Returns:
            List of Task instances

        Example:
            >>> tasks = await manager.list_blocked_by("issue_456")
        """
        from better_notion.plugins.official.agents_sdk.models import Task

        database_id = self._get_database_id("Tasks")
        if not database_id:
            return []

        response = await self._client._api._request(
            "POST",
            f"/databases/{database_id}/query",
            json={
                "filter": {
                    "property": "Related Work Issue",
                    "relation": {"contains": work_issue_id}
                }
            }
        )

        return [
            Task(self._client, page_data)
            for page_data in response.get("results", [])
        ]

    async def search(
        self,
        query: str,
        status: str | None = None,
        type_: str | None = None,
        severity: str | None = None,
        project_id: str | None = None,
        limit: int = 50,
    ) -> list[dict]:
        """Search work issues by text query with optional filters.

        Args:
            query: Text search query
            status: Optional status filter
            type_: Optional type filter
            severity: Optional severity filter
            project_id: Optional project ID filter
            limit: Maximum results to return

        Returns:
            List of search result dictionaries
        """
        from better_notion.plugins.official.agents_sdk.search import TextSearcher

        database_id = self._get_database_id("Work_issues")
        if not database_id:
            return []

        # Build filters
        filters: list[dict[str, Any]] = []

        if status:
            filters.append({"property": "Status", "select": {"equals": status}})

        if type_:
            filters.append({"property": "Type", "select": {"equals": type_}})

        if severity:
            filters.append({"property": "Severity", "select": {"equals": severity}})

        if project_id:
            filters.append({"property": "Project", "relation": {"contains": project_id}})

        # Combine filters
        filter_dict = None
        if filters:
            if len(filters) == 1:
                filter_dict = filters[0]
            else:
                filter_dict = {"and": filters}

        searcher = TextSearcher(self._client)
        results = await searcher.search_work_issues(query, database_id, filter_dict, limit)

        return [r.to_dict() for r in results]

    def _get_database_id(self, name: str) -> str | None:
        """Get database ID from workspace config."""
        return getattr(self._client, "_workspace_config", {}).get(name)


class IncidentManager:
    """
    Manager for Incident entities.

    Provides convenience methods for working with incidents,
    including finding SLA violations and calculating MTTR.
    """

    def __init__(self, client: "NotionClient") -> None:
        """Initialize manager with NotionClient instance."""
        self._client = client

    async def list(
        self,
        project_id: str | None = None,
        version_id: str | None = None,
        severity: str | None = None,
        status: str | None = None,
    ) -> list:
        """
        List Incidents with optional filtering.

        Args:
            project_id: Filter by project ID
            version_id: Filter by affected version ID
            severity: Filter by severity
            status: Filter by status

        Returns:
            List of Incident instances
        """
        from better_notion.plugins.official.agents_sdk.models import Incident

        database_id = self._get_database_id("Incidents")
        if not database_id:
            return []

        # Build filters
        filters = []

        if project_id:
            filters.append({
                "property": "Project",
                "relation": {"contains": project_id}
            })

        if version_id:
            filters.append({
                "property": "Affected Version",
                "relation": {"contains": version_id}
            })

        if severity:
            filters.append({
                "property": "Severity",
                "select": {"equals": severity}
            })

        if status:
            filters.append({
                "property": "Status",
                "select": {"equals": status}
            })

        # Query database
        query = {}
        if filters:
            if len(filters) == 1:
                query["filter"] = filters[0]
            else:
                query["filter"] = {
                    "and": filters
                }

        response = await self._client._api._request(
            "POST",
            f"/databases/{database_id}/query",
            json=query,
        )

        # Create Incident instances
        incidents = []
        for page_data in response.get("results", []):
            incident = Incident(self._client, page_data)
            incidents.append(incident)

        return incidents

    async def search(
        self,
        query: str,
        status: str | None = None,
        severity: str | None = None,
        incident_type: str | None = None,
        project_id: str | None = None,
        limit: int = 50,
    ) -> list[dict]:
        """Search incidents by text query with optional filters.

        Args:
            query: Text search query
            status: Optional status filter
            severity: Optional severity filter
            incident_type: Optional incident type filter
            project_id: Optional project ID filter
            limit: Maximum results to return

        Returns:
            List of search result dictionaries
        """
        from better_notion.plugins.official.agents_sdk.search import TextSearcher

        database_id = self._get_database_id("Incidents")
        if not database_id:
            return []

        # Build filters
        filters: list[dict[str, Any]] = []

        if status:
            filters.append({"property": "Status", "select": {"equals": status}})

        if severity:
            filters.append({"property": "Severity", "select": {"equals": severity}})

        if incident_type:
            filters.append({"property": "Type", "select": {"equals": incident_type}})

        if project_id:
            filters.append({"property": "Project", "relation": {"contains": project_id}})

        # Combine filters
        filter_dict = None
        if filters:
            if len(filters) == 1:
                filter_dict = filters[0]
            else:
                filter_dict = {"and": filters}

        searcher = TextSearcher(self._client)
        results = await searcher.search_incidents(query, database_id, filter_dict, limit)

        return [r.to_dict() for r in results]

    async def triage(self, incident_id: str) -> dict:
        """Triage and classify an incident.

        Args:
            incident_id: Incident ID to triage

        Returns:
            Dictionary with triage results including severity, type, and suggested assignment
        """
        from better_notion.plugins.official.agents_sdk.agent import IncidentTriager
        from better_notion.plugins.official.agents_sdk.models import Incident

        incident = await Incident.get(incident_id, client=self._client)
        triager = IncidentTriager(self._client)

        return await triager.triage_incident(incident)

    async def find_sla_violations(self) -> list:
        """
        Find all incidents that violated SLA.

        SLA: Critical incidents should be resolved within 4 hours.

        Returns:
            List of Incident instances with SLA violations
        """
        from datetime import timedelta

        incidents = await self.list()

        violations = []
        for incident in incidents:
            if incident.severity == "Critical" and incident.resolved_date:
                # SLA: 4 hours for Critical
                sla_hours = 4
                sla_duration = timedelta(hours=sla_hours)

                if incident.discovery_date:
                    resolution_time = incident.resolved_date - incident.discovery_date
                    if resolution_time > sla_duration:
                        violations.append(incident)

        return violations

    async def calculate_mttr(
        self, project_id: str | None = None, within_days: int = 30
    ) -> dict[str, float]:
        """
        Calculate Mean Time To Resolve (MTTR) for incidents.

        Args:
            project_id: Filter by project ID (optional)
            within_days: Only consider incidents from last N days

        Returns:
            Dictionary mapping severity to MTTR in hours
        """
        from datetime import datetime, timedelta, timezone

        cutoff_date = datetime.now(timezone.utc) - timedelta(days=within_days)
        incidents = await self.list(project_id=project_id)

        # Filter by date and resolved status
        resolved_incidents = [
            i for i in incidents
            if i.status == "Resolved"
            and i.discovery_date
            and i.resolved_date
            and i.discovery_date >= cutoff_date
        ]

        # Group by severity
        by_severity = {}
        for incident in resolved_incidents:
            severity = incident.severity or "Unknown"
            if severity not in by_severity:
                by_severity[severity] = []

            # Calculate resolution time in hours
            resolution_time = incident.resolved_date - incident.discovery_date
            hours = resolution_time.total_seconds() / 3600
            by_severity[severity].append(hours)

        # Calculate averages
        mttr = {}
        for severity, times in by_severity.items():
            mttr[severity] = sum(times) / len(times) if times else 0.0

        return mttr

    async def link_to_work_issue(self, incident_id: str, work_issue_id: str) -> dict:
        """
        Link an incident to a work issue (root cause).

        Args:
            incident_id: Incident ID
            work_issue_id: Work issue ID to link to

        Returns:
            Dict with incident_id and work_issue_id

        Example:
            >>> result = await manager.link_to_work_issue("inc_123", "issue_456")
        """
        from better_notion.plugins.official.agents_sdk.models import Incident

        incident = await Incident.get(incident_id, client=self._client)
        await incident.link_to_work_issue(work_issue_id)

        return {
            "incident_id": incident_id,
            "work_issue_id": work_issue_id,
            "linked": True
        }

    async def unlink_work_issue(self, incident_id: str) -> dict:
        """
        Unlink an incident from its work issue.

        Args:
            incident_id: Incident ID

        Returns:
            Dict with incident_id and unlinked status

        Example:
            >>> result = await manager.unlink_work_issue("inc_123")
        """
        from better_notion.plugins.official.agents_sdk.models import Incident

        incident = await Incident.get(incident_id, client=self._client)
        await incident.unlink_work_issue()

        return {
            "incident_id": incident_id,
            "unlinked": True
        }

    async def list_caused_by(self, work_issue_id: str) -> list:
        """
        List all incidents caused by a work issue.

        Args:
            work_issue_id: Work issue ID

        Returns:
            List of Incident instances

        Example:
            >>> incidents = await manager.list_caused_by("issue_456")
        """
        from better_notion.plugins.official.agents_sdk.models import Incident

        database_id = self._get_database_id("Incidents")
        if not database_id:
            return []

        response = await self._client._api._request(
            "POST",
            f"/databases/{database_id}/query",
            json={
                "filter": {
                    "property": "Root Cause Work Issue",
                    "relation": {"contains": work_issue_id}
                }
            }
        )

        return [
            Incident(self._client, page_data)
            for page_data in response.get("results", [])
        ]

    def _get_database_id(self, name: str) -> str | None:
        """Get database ID from workspace config."""
        return getattr(self._client, "_workspace_config", {}).get(name)
