#!/usr/bin/env python3
"""Add a comment and optional attachment to a Jira issue via REST API.

Uses Typer for elegant CLI, loads credentials from ~/.jira.env,
supports interactive multiline input and attachment notes.
"""

import getpass
import shutil
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
from .prompt_helper import read_multiline_input

app = typer.Typer(
    add_completion=False,
    help="Add a comment (with optional attachment) to a Jira issue.",
    epilog="Credentials are loaded from ~/.config/jps-jira-utils/.jira.env (JIRA_BASE_URL, JIRA_EMAIL, JIRA_API_TOKEN)",
)


def confirm_comment(text: str) -> bool:
    """Show comment and confirm with user.

    Args:
        text: The comment text to display.

    Returns:
        True if user confirms, False to abort.
    """
    typer.echo("\nYour comment:")
    typer.echo("-" * 60)
    typer.echo(text.strip() or "(empty)")
    typer.echo("-" * 60)
    return typer.confirm("Proceed with this comment?", default=True)


def get_attachment_note() -> str:
    """Prompt for pre-canned or custom attachment note.

    Returns:
        str: The selected or entered note text.
    """
    canned_options = [
        "This README.md outlines steps for testing and evaluation.",
        "This is the STDOUT.",
        "This is the STDERR.",
        "This is the log file.",
    ]

    use_canned = typer.confirm("Use pre-canned accompanying note?", default=True)
    if use_canned:
        typer.echo("Available notes:")
        for i, opt in enumerate(canned_options, 1):
            typer.echo(f"  {i}. {opt}")
        while True:
            choice = typer.prompt("Select (number or type part of text)", type=str)
            if choice.isdigit() and 1 <= int(choice) <= len(canned_options):
                return canned_options[int(choice) - 1]
            for opt in canned_options:
                if choice.lower() in opt.lower():
                    return opt
            typer.echo("Invalid selection. Try again.", err=True)
    else:
        return typer.prompt("Enter your one-line note", type=str).strip()


def get_comment_text(comment_file: Optional[Path], logger) -> str:
    """Get comment text from file or interactive input.

    Args:
        comment_file: Optional path to file containing comment text.
        logger: Logger instance.

    Returns:
        str: The comment text.

    Raises:
        Exit: If comment file not found or user cancels.
    """
    if comment_file:
        comment_file = comment_file.expanduser().resolve()
        if not comment_file.is_file():
            logger.error("Comment file not found: %s", comment_file)
            typer.echo(f"Error: Comment file not found: {comment_file}", err=True)
            raise typer.Exit(1)
        comment_text = comment_file.read_text(encoding="utf-8")
        logger.info("Loaded comment from %s", comment_file)
        return comment_text
    else:
        comment_text = read_multiline_input("Enter your comment (end with two blank lines):")
        if not confirm_comment(comment_text):
            logger.info("User aborted after comment entry")
            typer.echo("Cancelled.")
            raise typer.Exit(0)
        return comment_text


def validate_and_prepare_attachment(
    attach_file: Path, logger
) -> tuple[Path, Optional[str]]:
    """Validate attachment file and create timestamped copy if README.md.

    Args:
        attach_file: Path to the attachment file.
        logger: Logger instance.

    Returns:
        tuple: (attachment_path, readme_timestamp_name)

    Raises:
        Exit: If attachment validation fails.
    """
    attach_file = attach_file.expanduser().resolve()
    
    if not attach_file.exists():
        logger.error("Attachment not found: %s", attach_file)
        typer.echo(f"Error: Attachment file does not exist: {attach_file}", err=True)
        raise typer.Exit(1)
    if not attach_file.is_file():
        logger.error("Attachment path is not a file: %s", attach_file)
        typer.echo(f"Error: Not a regular file: {attach_file}", err=True)
        raise typer.Exit(1)
    if attach_file.stat().st_size == 0:
        logger.error("Attachment is empty: %s", attach_file)
        typer.echo(f"Error: Attachment file is empty: {attach_file}", err=True)
        raise typer.Exit(1)

    # If it's a README.md, create timestamped copy
    readme_timestamp_name = None
    if attach_file.name == "README.md":
        timestamp_formatted = datetime.now().strftime("%Y-%m-%d-%H%M")
        readme_timestamp_name = f"README-{timestamp_formatted}.md"
        timestamped_path = attach_file.parent / readme_timestamp_name
        shutil.copy2(attach_file, timestamped_path)
        attachment_path = timestamped_path
        logger.info("Created timestamped copy: %s", timestamped_path)
    else:
        attachment_path = attach_file

    logger.info(
        "Validated attachment: %s (%d bytes)", attachment_path, attachment_path.stat().st_size
    )
    
    return attachment_path, readme_timestamp_name


def show_final_confirmation(
    jira_id: str,
    jira_url: str,
    comment_text: str,
    attachment_path: Optional[Path],
    attachment_note: Optional[str],
    logger,
) -> None:
    """Show final review and confirm before posting.

    Args:
        jira_id: Jira issue key.
        jira_url: Full Jira URL.
        comment_text: The comment text.
        attachment_path: Path to attachment if any.
        attachment_note: Attachment note if any.
        logger: Logger instance.

    Raises:
        Exit: If user cancels.
    """
    typer.echo("\n" + "=" * 70)
    typer.echo("FINAL REVIEW - ABOUT TO POST")
    typer.echo("=" * 70)
    typer.echo(f"Jira Ticket       : {jira_id}")
    typer.echo(f"Jira URL          : {jira_url}")
    typer.echo(
        f"Comment           : {'(empty)' if not comment_text.strip() else comment_text.splitlines()[0]}{' ...' if len(comment_text.splitlines()) > 1 else ''}"  # noqa: E501
    )
    typer.echo(f"Attachment        : {attachment_path or 'None'}")
    typer.echo(f"Attachment Note   : {attachment_note or 'None'}")
    typer.echo("=" * 70)

    if not typer.confirm("Proceed and post to Jira?", default=True):
        logger.info("User cancelled at final confirmation")
        typer.echo("Cancelled.")
        raise typer.Exit(0)


def build_comment_body(
    comment_text: str, readme_timestamp_name: Optional[str], attachment_note: Optional[str]
) -> str:
    """Build the full comment body with all components.

    Args:
        comment_text: User-provided comment text.
        readme_timestamp_name: Name of timestamped README if applicable.
        attachment_note: Attachment note if any.

    Returns:
        str: The complete comment body.
    """
    full_comment = ""
    
    # If README was timestamped, add the "Attached README-..." line first
    if readme_timestamp_name:
        full_comment = f"Attached {readme_timestamp_name}."
    
    # Add user comment (strip trailing newlines from multiline input)
    if comment_text.strip():
        if full_comment:
            full_comment += "\n\n"
        full_comment += comment_text.strip()
    
    # Add attachment note if provided
    if attachment_note:
        if full_comment:
            full_comment += "\n\n"
        full_comment += attachment_note

    return full_comment


def post_comment(session: requests.Session, base_url: str, jira_id: str, comment_body: str, logger) -> str:
    """Post comment to Jira via REST API.

    Args:
        session: Authenticated requests session.
        base_url: Jira base URL.
        jira_id: Jira issue key.
        comment_body: The comment text to post.
        logger: Logger instance.

    Returns:
        str: The created comment ID.

    Raises:
        Exit: If comment posting fails.
    """
    payload = {
        "body": {
            "type": "doc",
            "version": 1,
            "content": [{"type": "paragraph", "content": [{"type": "text", "text": comment_body}]}],
        }
    }

    comment_url = f"{base_url}/rest/api/3/issue/{jira_id}/comment"
    logger.info("POST comment → %s", comment_url)
    resp = session.post(comment_url, json=payload)
    if not resp.ok:
        logger.error("Comment failed: %d %s", resp.status_code, resp.text)
        typer.echo(f"Failed to add comment: {resp.status_code}", err=True)
        typer.echo(resp.text, err=True)
        raise typer.Exit(1)

    comment_id = resp.json().get("id")
    logger.info("Comment created: %s", comment_id)
    return comment_id


def upload_attachment(
    session: requests.Session, base_url: str, jira_id: str, attachment_path: Path, logger
) -> None:
    """Upload attachment to Jira issue.

    Args:
        session: Authenticated requests session.
        base_url: Jira base URL.
        jira_id: Jira issue key.
        attachment_path: Path to file to attach.
        logger: Logger instance.
    """
    files = {"file": (attachment_path.name, open(attachment_path, "rb"))}
    attach_url = f"{base_url}/rest/api/3/issue/{jira_id}/attachments"
    headers = {"X-Atlassian-Token": "nocheck"}
    logger.info("Uploading attachment → %s", attach_url)
    resp = session.post(attach_url, headers=headers, files=files)
    if resp.ok:
        logger.info("Attachment uploaded successfully")
    else:
        logger.error("Attachment upload failed: %d %s", resp.status_code, resp.text)
        typer.echo(f"Warning: Attachment upload failed: {resp.status_code}", err=True)


@app.command()
def main(
    jira_id: str = typer.Argument(..., help="Jira issue key, e.g. JPS-1220"),
    comment_file: Optional[Path] = typer.Option(
        None, "--comment-file", help="File containing comment text"
    ),
    attach_file: Optional[Path] = typer.Option(
        None, "--attach-file", help="File to attach to the comment"
    ),
    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>/add_comment.py/<timestamp>/add_comment.py.log)",
    ),
) -> None:
    """Add a comment and optional attachment to a Jira issue.

    Args:
        jira_id: The Jira issue key (e.g. JPS-1220).
        comment_file: Optional file path to load comment from.
        attach_file: Optional file path to attach.
        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() / "add_comment.py" / timestamp
    log_file = logfile or (default_log_dir / "add_comment.py.log")
    log_file = log_file.expanduser().resolve()

    logger = setup_logging(log_file)
    logger.info("=== add_comment.py started ===")
    logger.info("Jira ID: %s", jira_id)
    logger.info("Comment file: %s", comment_file)
    logger.info("Attach file: %s", attach_file)

    # 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"})

    jira_url = f"{base_url}/browse/{jira_id}"
    logger.info("Jira URL: %s", jira_url)

    # Get comment text
    comment_text = get_comment_text(comment_file, logger)

    # Handle attachment
    attachment_path: Optional[Path] = None
    attachment_note: Optional[str] = None
    readme_timestamp_name: Optional[str] = None

    if attach_file:
        attachment_path, readme_timestamp_name = validate_and_prepare_attachment(attach_file, logger)
        
        if typer.confirm("Add accompanying note for attachment?", default=True):
            attachment_note = get_attachment_note()

    # Final confirmation
    show_final_confirmation(
        jira_id, jira_url, comment_text, attachment_path, attachment_note, logger
    )

    # Build and post comment
    full_comment = build_comment_body(comment_text, readme_timestamp_name, attachment_note)
    post_comment(session, base_url, jira_id, full_comment, logger)

    # Upload attachment if provided
    if attachment_path:
        upload_attachment(session, base_url, jira_id, attachment_path, logger)

    # Success
    typer.echo(f"\nSuccess! Comment added to {jira_id}")
    typer.echo(f"Jira URL: {jira_url}")
    typer.echo(f"Wrote the log file to '{log_file}'")


if __name__ == "__main__":
    app()
