"""
Comment Triggers - Handle /groknroll commands from GitHub comments

Provides the execution flow for responding to GitHub comment triggers:
- Parse comments for /groknroll or /gknr commands
- Extract task and agent from comment
- Execute groknroll with the task
- Post result as reply comment

Examples:
    # Create trigger handler
    handler = CommentTriggerHandler(github_token="...")

    # Process a webhook event
    result = await handler.process_event(event)

    # Handle comment directly
    result = await handler.handle_comment(
        repo="owner/repo",
        issue_number=42,
        comment_body="/groknroll fix the bug",
    )
"""

from dataclasses import dataclass, field
from enum import Enum, auto
from typing import Any, Callable, Optional

import httpx

from groknroll.github.comments import CommentParser, ParsedComment


class TriggerStatus(Enum):
    """Status of trigger execution"""

    PENDING = auto()
    RUNNING = auto()
    SUCCESS = auto()
    FAILURE = auto()
    SKIPPED = auto()  # No trigger found


@dataclass
class TriggerResult:
    """Result of processing a trigger"""

    status: TriggerStatus
    task: Optional[str] = None
    agent: Optional[str] = None
    output: str = ""
    error: Optional[str] = None
    comment_id: Optional[int] = None  # ID of posted reply comment
    metadata: dict[str, Any] = field(default_factory=dict)

    @property
    def success(self) -> bool:
        """Check if trigger was successful"""
        return self.status == TriggerStatus.SUCCESS

    @property
    def has_trigger(self) -> bool:
        """Check if a trigger was found"""
        return self.status != TriggerStatus.SKIPPED


@dataclass
class CommentContext:
    """Context for a comment trigger"""

    repo: str  # "owner/repo" format
    issue_number: int
    comment_id: int
    comment_body: str
    author: str
    is_pr: bool = False
    pr_branch: Optional[str] = None
    parsed: Optional[ParsedComment] = None

    @property
    def owner(self) -> str:
        """Get repository owner"""
        return self.repo.split("/")[0]

    @property
    def repo_name(self) -> str:
        """Get repository name"""
        return self.repo.split("/")[1]


class CommentTriggerHandler:
    """
    Handler for comment triggers

    Processes GitHub comments, detects /groknroll commands,
    and executes the appropriate agent.

    Example:
        handler = CommentTriggerHandler(
            github_token="...",
            on_execute=lambda task, agent: run_groknroll(task, agent),
        )

        result = await handler.handle_comment(
            repo="owner/repo",
            issue_number=42,
            comment_body="/groknroll fix the auth bug",
        )
    """

    GITHUB_API_URL = "https://api.github.com"

    def __init__(
        self,
        github_token: Optional[str] = None,
        on_execute: Optional[Callable[[str, str], str]] = None,
        default_agent: str = "build",
        parser: Optional[CommentParser] = None,
    ):
        """
        Initialize handler

        Args:
            github_token: GitHub API token for posting comments
            on_execute: Callback to execute groknroll task
            default_agent: Default agent when not specified
            parser: Optional comment parser
        """
        self.github_token = github_token
        self.on_execute = on_execute
        self.default_agent = default_agent
        self.parser = parser or CommentParser()

    def parse_comment(self, comment_body: str) -> ParsedComment:
        """
        Parse a comment for triggers

        Args:
            comment_body: The comment text

        Returns:
            ParsedComment with trigger info
        """
        return self.parser.parse(comment_body)

    def has_trigger(self, comment_body: str) -> bool:
        """
        Check if comment has a trigger

        Args:
            comment_body: The comment text

        Returns:
            True if comment contains trigger
        """
        parsed = self.parse_comment(comment_body)
        return parsed.has_command

    async def handle_comment(
        self,
        repo: str,
        issue_number: int,
        comment_body: str,
        comment_id: int = 0,
        author: str = "",
        is_pr: bool = False,
        client: Optional[httpx.AsyncClient] = None,
    ) -> TriggerResult:
        """
        Handle a comment trigger

        Args:
            repo: Repository in "owner/repo" format
            issue_number: Issue or PR number
            comment_body: The comment text
            comment_id: Comment ID
            author: Comment author
            is_pr: Whether this is a PR comment
            client: Optional HTTP client

        Returns:
            TriggerResult with execution status
        """
        # Parse comment
        parsed = self.parse_comment(comment_body)

        if not parsed.has_command:
            return TriggerResult(status=TriggerStatus.SKIPPED)

        # Create context
        context = CommentContext(
            repo=repo,
            issue_number=issue_number,
            comment_id=comment_id,
            comment_body=comment_body,
            author=author,
            is_pr=is_pr,
            parsed=parsed,
        )

        # Extract task and agent
        task = parsed.command.task if parsed.command else ""
        agent = (
            parsed.command.agent if parsed.command and parsed.command.agent
            else self.default_agent
        )

        if not task:
            return TriggerResult(
                status=TriggerStatus.FAILURE,
                task=task,
                agent=agent,
                error="No task specified after trigger",
            )

        # Execute
        result = await self._execute_trigger(context, task, agent, client)
        return result

    async def _execute_trigger(
        self,
        context: CommentContext,
        task: str,
        agent: str,
        client: Optional[httpx.AsyncClient] = None,
    ) -> TriggerResult:
        """Execute the trigger and optionally post reply"""
        output = ""
        error = None
        status = TriggerStatus.PENDING

        # Execute groknroll
        if self.on_execute:
            try:
                output = self.on_execute(task, agent)
                status = TriggerStatus.SUCCESS
            except Exception as e:
                error = str(e)
                status = TriggerStatus.FAILURE
        else:
            # No executor configured, just mark as success
            output = f"Would execute: groknroll {agent} \"{task}\""
            status = TriggerStatus.SUCCESS

        result = TriggerResult(
            status=status,
            task=task,
            agent=agent,
            output=output,
            error=error,
            metadata={
                "repo": context.repo,
                "issue_number": context.issue_number,
                "author": context.author,
            },
        )

        # Post reply comment if we have a token
        if self.github_token:
            comment_id = await self._post_reply(context, result, client)
            result.comment_id = comment_id

        return result

    async def _post_reply(
        self,
        context: CommentContext,
        result: TriggerResult,
        client: Optional[httpx.AsyncClient] = None,
    ) -> Optional[int]:
        """Post a reply comment"""
        body = self._format_reply(result)

        close_client = client is None
        if client is None:
            client = httpx.AsyncClient()

        try:
            url = (
                f"{self.GITHUB_API_URL}/repos/{context.repo}"
                f"/issues/{context.issue_number}/comments"
            )
            headers = {
                "Authorization": f"token {self.github_token}",
                "Accept": "application/vnd.github+json",
            }

            response = await client.post(
                url,
                headers=headers,
                json={"body": body},
            )

            if response.status_code == 201:
                data = response.json()
                return data.get("id")
            return None

        except Exception:
            return None
        finally:
            if close_client:
                await client.aclose()

    def _format_reply(self, result: TriggerResult) -> str:
        """Format reply comment"""
        if result.success:
            return (
                f"### groknroll completed\n\n"
                f"**Task**: {result.task}\n"
                f"**Agent**: {result.agent}\n\n"
                f"```\n{result.output[:2000]}\n```"
            )
        else:
            return (
                f"### groknroll failed\n\n"
                f"**Task**: {result.task}\n"
                f"**Error**: {result.error or 'Unknown error'}\n"
            )


def format_trigger_response(result: TriggerResult) -> str:
    """
    Format trigger result for display

    Args:
        result: TriggerResult to format

    Returns:
        Formatted string
    """
    if result.status == TriggerStatus.SKIPPED:
        return "No trigger found"

    lines = [
        f"Status: {result.status.name}",
        f"Task: {result.task or 'N/A'}",
        f"Agent: {result.agent or 'N/A'}",
    ]

    if result.output:
        lines.append(f"Output: {result.output[:200]}...")

    if result.error:
        lines.append(f"Error: {result.error}")

    return "\n".join(lines)


def extract_trigger_info(comment: str) -> dict[str, Any]:
    """
    Extract trigger info from comment

    Args:
        comment: Comment text

    Returns:
        Dict with trigger info
    """
    parser = CommentParser()
    parsed = parser.parse(comment)

    if not parsed.has_command:
        return {"has_trigger": False}

    return {
        "has_trigger": True,
        "trigger": parsed.command.trigger if parsed.command else None,
        "task": parsed.command.task if parsed.command else None,
        "agent": parsed.command.agent if parsed.command else None,
    }
