#!/usr/bin/env python3
"""Create a new Jira issue via REST API.

Uses Typer for elegant CLI, loads credentials from config file,
supports interactive input for issue details.
"""

import getpass
from datetime import datetime
from pathlib import Path
from typing import Optional

import requests
import typer
from requests.auth import HTTPBasicAuth

from .jira_helper import load_jira_env
from .logging_helper import setup_logging

app = typer.Typer(
    add_completion=False,
    help="Create a new Jira issue.",
    epilog="Credentials are loaded from ~/.config/jps-jira-utils/.jira.env (JIRA_BASE_URL, JIRA_EMAIL, JIRA_API_TOKEN)",
)


def get_issue_types(session: requests.Session, base_url: str, project_key: str, logger) -> list[dict]:
    """Get available issue types for a project.

    Args:
        session: Authenticated requests session.
        base_url: Jira base URL.
        project_key: The project key.
        logger: Logger instance.

    Returns:
        list: Available issue types.

    Raises:
        Exit: If fetching issue types fails.
    """
    url = f"{base_url}/rest/api/3/issue/createmeta"
    params = {"projectKeys": project_key, "expand": "projects.issuetypes"}
    logger.info("Fetching issue types for project %s", project_key)
    
    resp = session.get(url, params=params)
    if not resp.ok:
        logger.error("Failed to fetch issue types: %d %s", resp.status_code, resp.text)
        typer.echo(f"Error: Failed to fetch issue types: {resp.status_code}", err=True)
        raise typer.Exit(1)
    
    data = resp.json()
    if not data.get("projects"):
        logger.error("Project not found: %s", project_key)
        typer.echo(f"Error: Project not found: {project_key}", err=True)
        raise typer.Exit(1)
    
    issue_types = data["projects"][0].get("issuetypes", [])
    logger.info("Found %d issue types", len(issue_types))
    return issue_types


def get_current_user(session: requests.Session, base_url: str, logger) -> dict:
    """Get current authenticated user's account information.

    Args:
        session: Authenticated requests session.
        base_url: Jira base URL.
        logger: Logger instance.

    Returns:
        dict: User information including accountId.

    Raises:
        Exit: If fetching user info fails.
    """
    url = f"{base_url}/rest/api/3/myself"
    logger.info("Fetching current user information")
    
    resp = session.get(url)
    if not resp.ok:
        logger.error("Failed to fetch user info: %d %s", resp.status_code, resp.text)
        typer.echo(f"Error: Failed to fetch user information: {resp.status_code}", err=True)
        raise typer.Exit(1)
    
    user_info = resp.json()
    logger.info("Current user: %s (accountId: %s)", user_info.get("emailAddress"), user_info.get("accountId"))
    return user_info


def prompt_for_issue_type(issue_types: list[dict]) -> str:
    """Prompt user to select an issue type.

    Args:
        issue_types: List of available issue types.

    Returns:
        str: Selected issue type name.

    Raises:
        Exit: If no issue types available or user cancels.
    """
    if not issue_types:
        typer.echo("Error: No issue types available for this project.", err=True)
        raise typer.Exit(1)
    
    typer.echo("\nAvailable issue types:")
    for i, it in enumerate(issue_types, 1):
        typer.echo(f"  {i}. {it['name']}")
    
    while True:
        choice = typer.prompt("Select issue type (number or name)", type=str)
        
        # Try numeric selection
        if choice.isdigit():
            idx = int(choice) - 1
            if 0 <= idx < len(issue_types):
                return issue_types[idx]["name"]
        
        # Try name match (case-insensitive)
        for it in issue_types:
            if choice.lower() == it["name"].lower():
                return it["name"]
        
        typer.echo("Invalid selection. Try again.", err=True)


def create_issue(
    session: requests.Session,
    base_url: str,
    project_key: str,
    issue_type: str,
    summary: str,
    description: Optional[str],
    reporter_account_id: str,
    logger,
) -> tuple[str, str]:
    """Create a Jira issue.

    Required fields (per Jira configuration):
    - Space (project)
    - Work Type (issuetype)
    - Reporter
    - Title (summary)

    Args:
        session: Authenticated requests session.
        base_url: Jira base URL.
        project_key: The project key (Space).
        issue_type: The issue type name (Work Type).
        summary: Issue summary (Title).
        description: Optional issue description.
        reporter_account_id: Account ID of the reporter (authenticated user).
        logger: Logger instance.

    Returns:
        tuple: (issue_key, issue_url)

    Raises:
        Exit: If issue creation fails.
    """
    # Build description content in Atlassian Document Format (ADF)
    description_content = []
    if description and description.strip():
        description_content = [
            {
                "type": "paragraph",
                "content": [{"type": "text", "text": description.strip()}],
            }
        ]
    
    payload = {
        "fields": {
            "project": {"key": project_key},
            "summary": summary,
            "issuetype": {"name": issue_type},
            "reporter": {"accountId": reporter_account_id},
        }
    }
    
    # Add description if provided
    if description_content:
        payload["fields"]["description"] = {
            "type": "doc",
            "version": 1,
            "content": description_content,
        }
    
    url = f"{base_url}/rest/api/3/issue"
    logger.info("Creating issue in project %s", project_key)
    logger.info("Issue type: %s", issue_type)
    logger.info("Summary: %s", summary)
    logger.info("Reporter account ID: %s", reporter_account_id)
    
    resp = session.post(url, json=payload)
    if not resp.ok:
        logger.error("Failed to create issue: %d %s", resp.status_code, resp.text)
        typer.echo(f"Error: Failed to create issue: {resp.status_code}", err=True)
        typer.echo(resp.text, err=True)
        raise typer.Exit(1)
    
    result = resp.json()
    issue_key = result.get("key")
    issue_url = f"{base_url}/browse/{issue_key}"
    
    logger.info("Created issue: %s", issue_key)
    return issue_key, issue_url


@app.command()
def main(
    project_key: str = typer.Argument(..., help="Jira project key (Space), e.g. JPS"),
    summary: Optional[str] = typer.Option(None, "--summary", "-s", help="Issue summary/title (Title)"),
    description: Optional[str] = typer.Option(None, "--description", "-d", help="Issue description"),
    issue_type: Optional[str] = typer.Option(
        None, "--issue-type", "-t", help="Issue type (Work Type) - e.g., Task, Bug, Story"
    ),
    reporter: Optional[str] = typer.Option(
        None, "--reporter", "-r", help="Reporter email address (defaults to authenticated user's email)"
    ),
    config_file: Optional[Path] = typer.Option(
        None,
        "--config-file",
        help="Path to config file (default: ~/.config/jps-jira-utils/.jira.env)",
    ),
    logfile: Optional[Path] = typer.Option(
        None,
        "--logfile",
        help="Custom log file path (default: /tmp/<user>/create_issue.py/<timestamp>/create_issue.py.log)",
    ),
) -> None:
    """Create a new Jira issue.

    Required fields:
    - Space (project_key): Project key
    - Work Type (issue_type): Type of issue to create
    - Reporter: Email of the person creating the issue
    - Title (summary): Brief description of the issue

    Args:
        project_key: The Jira project key (Space), e.g. JPS.
        summary: Issue summary (Title). Will be prompted if not provided.
        description: Optional issue description.
        issue_type: Issue type (Work Type). Will be prompted if not provided.
        reporter: Reporter email address. Defaults to authenticated user's email.
        config_file: Optional path to configuration file.
        logfile: Optional custom log file path.

    Raises:
        Exit: On error or user cancellation.
    """
    # Setup logging
    timestamp = datetime.now().strftime("%Y-%m-%d-%H%M%S")
    default_log_dir = Path("/tmp") / getpass.getuser() / "create_issue.py" / timestamp
    log_file = logfile or (default_log_dir / "create_issue.py.log")
    log_file = log_file.expanduser().resolve()

    logger = setup_logging(log_file)
    logger.info("=== create_issue.py started ===")
    logger.info("Project key: %s", project_key)

    # Setup Jira session
    base_url, email, token = load_jira_env(config_file)
    auth = HTTPBasicAuth(email, token)
    session = requests.Session()
    session.auth = auth
    session.headers.update({"Accept": "application/json", "Content-Type": "application/json"})

    # Get current user's account information
    current_user = get_current_user(session, base_url, logger)
    reporter_account_id = current_user.get("accountId")
    reporter_display = current_user.get("emailAddress") or current_user.get("displayName")
    
    # Allow override of reporter if specified (get account ID by email)
    if reporter:
        # If custom reporter is specified, we'd need to look them up
        # For now, we'll just use the authenticated user
        logger.warning("Custom reporter specified but using authenticated user's account ID")
    
    logger.info("Reporter: %s (accountId: %s)", reporter_display, reporter_account_id)

    # Get available issue types
    issue_types = get_issue_types(session, base_url, project_key, logger)

    # Get issue type (prompt if not provided)
    if not issue_type:
        issue_type = prompt_for_issue_type(issue_types)
    else:
        # Validate provided issue type
        valid_types = [it["name"].lower() for it in issue_types]
        if issue_type.lower() not in valid_types:
            typer.echo(f"Error: Invalid issue type '{issue_type}'", err=True)
            typer.echo(f"Valid types: {', '.join([it['name'] for it in issue_types])}", err=True)
            raise typer.Exit(1)
    
    logger.info("Selected issue type: %s", issue_type)

    # Get summary (prompt if not provided)
    if not summary:
        summary = typer.prompt("Enter issue summary (Title)")
    
    # Ensure summary is not empty (type narrowing)
    if not summary or not summary.strip():
        typer.echo("Error: Summary cannot be empty", err=True)
        raise typer.Exit(1)

    # Get description (prompt if not provided)
    if description is None:
        if typer.confirm("Add a description?", default=True):
            description = typer.prompt("Enter description", type=str, default="")

    # Final confirmation
    typer.echo("\n" + "=" * 70)
    typer.echo("ISSUE DETAILS - ABOUT TO CREATE")
    typer.echo("=" * 70)
    typer.echo(f"Space (Project)   : {project_key}")
    typer.echo(f"Work Type         : {issue_type}")
    typer.echo(f"Title (Summary)   : {summary}")
    typer.echo(f"Reporter          : {reporter_display}")
    typer.echo(f"Description       : {description[:50] + '...' if description and len(description) > 50 else description or '(none)'}")
    typer.echo("=" * 70)

    if not typer.confirm("Create this issue?", default=True):
        logger.info("User cancelled at final confirmation")
        typer.echo("Cancelled.")
        raise typer.Exit(0)

    # Create the issue
    issue_key, issue_url = create_issue(
        session, base_url, project_key, issue_type, summary, description, reporter_account_id, logger
    )

    # Success
    typer.echo(f"\n✓ Success! Created issue {issue_key}")
    typer.echo(f"URL: {issue_url}")
    typer.echo(f"Log file: {log_file}")


if __name__ == "__main__":
    app()
