"""Issue tracking and management commands."""

from pathlib import Path
from typing import List, Optional

import typer
from rich.console import Console
from rich.panel import Panel
from rich.table import Table

from ai_trackdown_pytools.core.project import Project
from ai_trackdown_pytools.core.task import TaskManager
from ai_trackdown_pytools.utils.templates import TemplateManager

app = typer.Typer(help="Issue tracking and management")
console = Console()


@app.command()
def create(
    title: Optional[str] = typer.Argument(None, help="Issue title"),
    description: Optional[str] = typer.Option(
        None,
        "--description",
        "-d",
        help="Issue description",
    ),
    issue_type: Optional[str] = typer.Option(
        "bug",
        "--type",
        help="Issue type (bug, feature, enhancement, documentation)",
    ),
    severity: Optional[str] = typer.Option(
        "medium",
        "--severity",
        "-s",
        help="Issue severity (low, medium, high, critical)",
    ),
    assignee: Optional[str] = typer.Option(
        None,
        "--assignee",
        "-a",
        help="Issue assignee",
    ),
    label: Optional[List[str]] = typer.Option(
        None,
        "--label",
        "-l",
        help="Issue label (can be specified multiple times)",
    ),
    component: Optional[str] = typer.Option(
        None,
        "--component",
        "-c",
        help="Affected component",
    ),
    template: Optional[str] = typer.Option(
        None,
        "--template",
        help="Issue template to use",
    ),
    relates_to: Optional[str] = typer.Option(
        None,
        "--relates-to",
        help="Related task/issue ID",
    ),
) -> None:
    """Create a new issue."""
    project_path = Path.cwd()
    
    if not Project.exists(project_path):
        console.print("[red]No AI Trackdown project found[/red]")
        raise typer.Exit(1)
    
    task_manager = TaskManager(project_path)
    
    if not title:
        from rich.prompt import Prompt
        title = Prompt.ask("Issue title")
    
    if not description:
        from rich.prompt import Prompt
        description = Prompt.ask("Issue description", default="")
    
    # Build issue tags
    issue_tags = ["issue", issue_type or "bug"]
    if label:
        issue_tags.extend(label)
    
    # Apply template if specified
    issue_data = {
        "title": title,
        "description": description,
        "tags": issue_tags,
        "priority": severity or "medium",
        "assignees": [assignee] if assignee else [],
        "metadata": {
            "type": "issue",
            "issue_type": issue_type,
            "severity": severity,
            "component": component,
            "labels": label or [],
            "relates_to": relates_to,
            "resolution": None,
            "reported_by": None,
        }
    }
    
    if template:
        template_manager = TemplateManager()
        template_data = template_manager.load_template("issue", template)
        if template_data:
            issue_data.update(template_data)
            console.print(f"[green]Applied template: {template}[/green]")
    
    new_issue = task_manager.create_task(**issue_data)
    
    console.print(Panel.fit(
        f"""[bold green]Issue created successfully![/bold green]

[dim]ID:[/dim] {new_issue.id}
[dim]Title:[/dim] {new_issue.title}
[dim]Type:[/dim] {issue_type}
[dim]Severity:[/dim] {severity}
[dim]Component:[/dim] {component or 'None'}
[dim]Assignee:[/dim] {assignee or 'Unassigned'}
[dim]File:[/dim] {new_issue.file_path}""",
        title="Issue Created",
        border_style="red"
    ))


@app.command()
def list(
    status_filter: Optional[str] = typer.Option(None, "--status", "-s", help="Filter by status"),
    type_filter: Optional[str] = typer.Option(None, "--type", "-t", help="Filter by issue type"),
    severity_filter: Optional[str] = typer.Option(None, "--severity", help="Filter by severity"),
    assignee_filter: Optional[str] = typer.Option(None, "--assignee", "-a", help="Filter by assignee"),
    component_filter: Optional[str] = typer.Option(None, "--component", "-c", help="Filter by component"),
    show_closed: bool = typer.Option(False, "--closed", help="Include closed issues"),
    limit: int = typer.Option(50, "--limit", "-l", help="Maximum number of issues to show"),
) -> None:
    """List issues with optional filtering."""
    project_path = Path.cwd()
    
    if not Project.exists(project_path):
        console.print("[red]No AI Trackdown project found[/red]")
        raise typer.Exit(1)
    
    task_manager = TaskManager(project_path)
    all_tasks = task_manager.list_tasks()
    
    # Filter issues
    issues = [task for task in all_tasks if "issue" in task.tags]
    
    # Apply filters
    if status_filter:
        issues = [issue for issue in issues if issue.status == status_filter]
    
    if type_filter:
        issues = [issue for issue in issues if issue.metadata.get("issue_type") == type_filter]
    
    if severity_filter:
        issues = [issue for issue in issues if issue.metadata.get("severity") == severity_filter]
    
    if assignee_filter:
        issues = [issue for issue in issues if assignee_filter in issue.assignees]
    
    if component_filter:
        issues = [issue for issue in issues if issue.metadata.get("component") == component_filter]
    
    if not show_closed:
        issues = [issue for issue in issues if issue.status not in ["completed", "cancelled"]]
    
    # Limit results
    issues = issues[:limit]
    
    if not issues:
        console.print("[yellow]No issues found[/yellow]")
        return
    
    table = Table(title=f"Issues ({len(issues)} found)")
    table.add_column("ID", style="cyan")
    table.add_column("Title", style="white")
    table.add_column("Type", style="blue")
    table.add_column("Severity", style="magenta")
    table.add_column("Status", style="green")
    table.add_column("Assignee", style="yellow")
    table.add_column("Component", style="dim")
    
    for issue in issues:
        assignee = ", ".join(issue.assignees) if issue.assignees else "Unassigned"
        
        table.add_row(
            issue.id,
            issue.title[:30] + "..." if len(issue.title) > 30 else issue.title,
            issue.metadata.get("issue_type", "unknown"),
            issue.metadata.get("severity", "unknown"),
            issue.status,
            assignee[:15] + "..." if len(assignee) > 15 else assignee,
            issue.metadata.get("component", "")
        )
    
    console.print(table)


@app.command()
def show(
    issue_id: str = typer.Argument(..., help="Issue ID to display"),
    detailed: bool = typer.Option(False, "--detailed", "-d", help="Show detailed information"),
) -> None:
    """Show detailed issue information."""
    project_path = Path.cwd()
    
    if not Project.exists(project_path):
        console.print("[red]No AI Trackdown project found[/red]")
        raise typer.Exit(1)
    
    task_manager = TaskManager(project_path)
    issue = task_manager.load_task(issue_id)
    
    if not issue or "issue" not in issue.tags:
        console.print(f"[red]Issue '{issue_id}' not found[/red]")
        raise typer.Exit(1)
    
    assignees = ", ".join(issue.assignees) if issue.assignees else "Unassigned"
    labels = ", ".join(issue.metadata.get("labels", [])) if issue.metadata.get("labels") else "None"
    
    info_text = f"""[bold red]Issue Details[/bold red]

[dim]ID:[/dim] {issue.id}
[dim]Title:[/dim] {issue.title}
[dim]Type:[/dim] {issue.metadata.get('issue_type', 'unknown')}
[dim]Severity:[/dim] {issue.metadata.get('severity', 'unknown')}
[dim]Status:[/dim] {issue.status}
[dim]Priority:[/dim] {issue.priority}
[dim]Component:[/dim] {issue.metadata.get('component', 'None')}
[dim]Assignees:[/dim] {assignees}
[dim]Labels:[/dim] {labels}
[dim]Created:[/dim] {issue.created_at.strftime('%Y-%m-%d %H:%M')}
[dim]Updated:[/dim] {issue.updated_at.strftime('%Y-%m-%d %H:%M')}"""
    
    if issue.metadata.get("relates_to"):
        info_text += f"\n[dim]Related to:[/dim] {issue.metadata.get('relates_to')}"
    
    if issue.metadata.get("resolution"):
        info_text += f"\n[dim]Resolution:[/dim] {issue.metadata.get('resolution')}"
    
    if detailed:
        info_text += f"\n\n[dim]Description:[/dim]\n{issue.description}"
        
        if issue.metadata.get("reported_by"):
            info_text += f"\n\n[dim]Reported by:[/dim] {issue.metadata.get('reported_by')}"
    
    console.print(Panel.fit(
        info_text,
        title="Issue Information",
        border_style="red"
    ))


@app.command()
def update(
    issue_id: str = typer.Argument(..., help="Issue ID to update"),
    title: Optional[str] = typer.Option(None, "--title", help="Update issue title"),
    description: Optional[str] = typer.Option(None, "--description", "-d", help="Update issue description"),
    status: Optional[str] = typer.Option(None, "--status", "-s", help="Update issue status"),
    severity: Optional[str] = typer.Option(None, "--severity", help="Update issue severity"),
    assignee: Optional[str] = typer.Option(None, "--assignee", "-a", help="Update issue assignee"),
    component: Optional[str] = typer.Option(None, "--component", "-c", help="Update affected component"),
    resolution: Optional[str] = typer.Option(None, "--resolution", "-r", help="Set issue resolution"),
    add_label: Optional[List[str]] = typer.Option(None, "--add-label", help="Add labels to issue"),
    remove_label: Optional[List[str]] = typer.Option(None, "--remove-label", help="Remove labels from issue"),
) -> None:
    """Update an existing issue."""
    project_path = Path.cwd()
    
    if not Project.exists(project_path):
        console.print("[red]No AI Trackdown project found[/red]")
        raise typer.Exit(1)
    
    task_manager = TaskManager(project_path)
    issue = task_manager.load_task(issue_id)
    
    if not issue or "issue" not in issue.tags:
        console.print(f"[red]Issue '{issue_id}' not found[/red]")
        raise typer.Exit(1)
    
    # Prepare update data
    updates = {}
    metadata_updates = {}
    
    if title:
        updates['title'] = title
    if description:
        updates['description'] = description
    if status:
        if status not in ['open', 'in_progress', 'completed', 'cancelled', 'blocked']:
            console.print(f"[red]Invalid status: {status}[/red]")
            console.print("Valid statuses: open, in_progress, completed, cancelled, blocked")
            raise typer.Exit(1)
        updates['status'] = status
    if severity:
        if severity not in ['low', 'medium', 'high', 'critical']:
            console.print(f"[red]Invalid severity: {severity}[/red]")
            console.print("Valid severities: low, medium, high, critical")
            raise typer.Exit(1)
        metadata_updates['severity'] = severity
        updates['priority'] = severity  # Sync priority with severity
    if assignee:
        updates['assignees'] = [assignee] if assignee else []
    if component:
        metadata_updates['component'] = component
    if resolution:
        metadata_updates['resolution'] = resolution
    
    # Handle label updates
    if add_label or remove_label:
        current_labels = set(issue.metadata.get("labels", []))
        if add_label:
            current_labels.update(add_label)
        if remove_label:
            current_labels.difference_update(remove_label)
        metadata_updates['labels'] = list(current_labels)
    
    if not updates and not metadata_updates:
        console.print("[yellow]No updates specified[/yellow]")
        return
    
    # Apply metadata updates
    if metadata_updates:
        issue.metadata.update(metadata_updates)
        updates['metadata'] = issue.metadata
    
    # Apply updates
    success = task_manager.update_task(issue_id, **updates)
    
    if success:
        console.print(Panel.fit(
            f"""[bold green]Issue updated successfully![/bold green]

[dim]ID:[/dim] {issue_id}
[dim]Updates applied:[/dim] {', '.join(list(updates.keys()) + list(metadata_updates.keys()))}""",
            title="Issue Updated",
            border_style="green"
        ))
    else:
        console.print(f"[red]Failed to update issue {issue_id}[/red]")
        raise typer.Exit(1)


@app.command()
def resolve(
    issue_id: str = typer.Argument(..., help="Issue ID to resolve"),
    resolution: str = typer.Option(..., "--resolution", "-r", help="Resolution description"),
    resolution_type: str = typer.Option(
        "fixed",
        "--type",
        "-t",
        help="Resolution type (fixed, wontfix, duplicate, invalid)"
    ),
) -> None:
    """Resolve an issue with a specific resolution."""
    project_path = Path.cwd()
    
    if not Project.exists(project_path):
        console.print("[red]No AI Trackdown project found[/red]")
        raise typer.Exit(1)
    
    task_manager = TaskManager(project_path)
    issue = task_manager.load_task(issue_id)
    
    if not issue or "issue" not in issue.tags:
        console.print(f"[red]Issue '{issue_id}' not found[/red]")
        raise typer.Exit(1)
    
    # Update issue with resolution
    issue.metadata.update({
        "resolution": resolution,
        "resolution_type": resolution_type,
        "resolved_at": issue.updated_at.isoformat()
    })
    
    status = "completed" if resolution_type == "fixed" else "cancelled"
    
    success = task_manager.update_task(
        issue_id,
        status=status,
        metadata=issue.metadata
    )
    
    if success:
        console.print(Panel.fit(
            f"""[bold green]Issue resolved successfully![/bold green]

[dim]ID:[/dim] {issue_id}
[dim]Status:[/dim] {status}
[dim]Resolution:[/dim] {resolution}
[dim]Type:[/dim] {resolution_type}""",
            title="Issue Resolved",
            border_style="green"
        ))
    else:
        console.print(f"[red]Failed to resolve issue {issue_id}[/red]")
        raise typer.Exit(1)


@app.command()
def close(
    issue_id: str = typer.Argument(..., help="Issue ID to close"),
    reason: Optional[str] = typer.Option(None, "--reason", "-r", help="Reason for closing"),
) -> None:
    """Close an issue."""
    project_path = Path.cwd()
    
    if not Project.exists(project_path):
        console.print("[red]No AI Trackdown project found[/red]")
        raise typer.Exit(1)
    
    task_manager = TaskManager(project_path)
    issue = task_manager.load_task(issue_id)
    
    if not issue or "issue" not in issue.tags:
        console.print(f"[red]Issue '{issue_id}' not found[/red]")
        raise typer.Exit(1)
    
    # Update issue metadata
    if reason:
        issue.metadata["close_reason"] = reason
    issue.metadata["closed_at"] = issue.updated_at.isoformat()
    
    success = task_manager.update_task(
        issue_id,
        status="completed",
        metadata=issue.metadata
    )
    
    if success:
        console.print(f"[green]Issue {issue_id} closed successfully[/green]")
        if reason:
            console.print(f"[dim]Reason: {reason}[/dim]")
    else:
        console.print(f"[red]Failed to close issue {issue_id}[/red]")
        raise typer.Exit(1)


@app.command()
def reopen(
    issue_id: str = typer.Argument(..., help="Issue ID to reopen"),
    reason: Optional[str] = typer.Option(None, "--reason", "-r", help="Reason for reopening"),
) -> None:
    """Reopen a closed issue."""
    project_path = Path.cwd()
    
    if not Project.exists(project_path):
        console.print("[red]No AI Trackdown project found[/red]")
        raise typer.Exit(1)
    
    task_manager = TaskManager(project_path)
    issue = task_manager.load_task(issue_id)
    
    if not issue or "issue" not in issue.tags:
        console.print(f"[red]Issue '{issue_id}' not found[/red]")
        raise typer.Exit(1)
    
    if issue.status not in ["completed", "cancelled"]:
        console.print(f"[yellow]Issue {issue_id} is not closed[/yellow]")
        return
    
    # Update issue metadata
    if reason:
        issue.metadata["reopen_reason"] = reason
    issue.metadata["reopened_at"] = issue.updated_at.isoformat()
    
    # Clear resolution if exists
    if "resolution" in issue.metadata:
        del issue.metadata["resolution"]
    if "resolution_type" in issue.metadata:
        del issue.metadata["resolution_type"]
    
    success = task_manager.update_task(
        issue_id,
        status="open",
        metadata=issue.metadata
    )
    
    if success:
        console.print(f"[green]Issue {issue_id} reopened successfully[/green]")
        if reason:
            console.print(f"[dim]Reason: {reason}[/dim]")
    else:
        console.print(f"[red]Failed to reopen issue {issue_id}[/red]")
        raise typer.Exit(1)


if __name__ == "__main__":
    app()