"""Command-line interface for Agent Berlin SDK.

This module provides CLI commands for downloading workflows and uploading reports.
"""

import json
from pathlib import Path
from typing import Optional

import click
import requests

from . import __version__
from .config import DEFAULT_BASE_URL
from .session import configure_session as _configure_session, load_session_config


@click.group()
@click.version_option(version=__version__, prog_name="agentberlin")
def main() -> None:
    """Agent Berlin CLI - Download and manage workflows."""
    pass


@main.command()
@click.option("--token", "-t", required=True, help="Authentication token from get_auth_token MCP tool")
@click.option("--domain", "-d", required=True, help="Project domain (e.g., example.com)")
@click.option("--config-path", help="Custom config file path")
def configure(token: str, domain: str, config_path: Optional[str]) -> None:
    """Configure session credentials for Agent Berlin."""
    _configure_session(token, domain, config_path)
    click.echo(f"Session configured for domain: {domain}")


@main.command()
@click.argument("workflow_id")
@click.option("--token", envvar="AGENTBERLIN_TOKEN", help="API token")
@click.option("--output", "-o", type=click.Path(), help="Output directory")
@click.option("--base-url", default=DEFAULT_BASE_URL, hidden=True)
def download_workflow(
    workflow_id: str,
    token: Optional[str],
    output: Optional[str],
    base_url: str,
) -> None:
    """Download a workflow to local files.

    WORKFLOW_ID is the workflow identifier.

    This downloads the workflow definition to local files that can be read
    by an LLM to understand and execute the workflow locally.
    """
    # Resolve token (same as SDK)
    if not token:
        config = load_session_config()
        token = config.get("token")

    if not token:
        raise click.ClickException(
            "No API token found. Set AGENTBERLIN_TOKEN or configure session first."
        )

    # Fetch workflow from API
    headers = {"Authorization": f"Bearer {token}"}
    url = f"{base_url}/workflows/{workflow_id}/download"

    try:
        resp = requests.get(url, headers=headers, timeout=30)
    except requests.RequestException as e:
        raise click.ClickException(f"Failed to connect to API: {e}")

    if resp.status_code == 404:
        raise click.ClickException(f"Workflow '{workflow_id}' not found or access denied.")
    if resp.status_code == 401:
        raise click.ClickException("Authentication failed. Check your token.")

    try:
        resp.raise_for_status()
    except requests.HTTPError as e:
        raise click.ClickException(f"API request failed: {e}")

    data = resp.json()

    # Determine output directory
    if output:
        out_dir = Path(output)
    else:
        out_dir = Path.cwd() / ".agentberlin" / "workflows" / workflow_id

    out_dir.mkdir(parents=True, exist_ok=True)
    scripts_dir = out_dir / "scripts"
    scripts_dir.mkdir(exist_ok=True)
    subagents_dir = out_dir / "subagents"
    subagents_dir.mkdir(exist_ok=True)

    # Write scripts as individual .py files
    script_files: list[str] = []
    for script in data.get("scripts", []):
        name = script["name"].replace(" ", "_").lower()
        filename = f"{name}.py"
        script_files.append(filename)

        # Add header comment to script
        deps = ", ".join(script.get("dependencies", []))
        header = f'''# Script: {script["name"]}
# Description: {script.get("description", "")}
# Dependencies: {deps}

'''
        # Add INPUT preamble for external LLM execution
        # This allows LLMs to pass inputs via stdin when INPUT is not injected by executor
        input_preamble = '''# INPUT handling: reads from stdin if INPUT not injected by executor
import sys as _sys, json as _json
if 'INPUT' not in dir():
    INPUT = _json.loads(_sys.stdin.read()) if not _sys.stdin.isatty() else None

'''
        (scripts_dir / filename).write_text(header + input_preamble + script.get("script", ""))

    # Write sub-agents as individual .md files
    subagent_files: list[str] = []
    for subagent in data.get("subagents", []):
        name = subagent["name"].replace(" ", "_").lower()
        filename = f"{name}.md"
        subagent_files.append(filename)

        header = f"# {subagent['name']}\n\n"
        (subagents_dir / filename).write_text(header + subagent.get("processing_guide", ""))

    # Generate README.md with all workflow content
    readme = _generate_readme(data, script_files, subagent_files)
    (out_dir / "README.md").write_text(readme)

    # Print confirmation
    click.echo(f"Downloaded workflow: {data.get('name', workflow_id)}")
    click.echo(f"Location: {out_dir}")
    click.echo("Files:")
    click.echo("  - README.md")
    for sf in script_files:
        click.echo(f"  - scripts/{sf}")
    for sf in subagent_files:
        click.echo(f"  - subagents/{sf}")


@main.command()
@click.argument("file_path", type=click.Path(exists=True))
@click.option("--description", "-d", required=True, help="Report description")
@click.option("--project-domain", help="Project domain (reads from config if not set)")
@click.option("--token", envvar="AGENTBERLIN_TOKEN", help="API token")
@click.option("--base-url", default=DEFAULT_BASE_URL, hidden=True)
def save_report(
    file_path: str,
    description: str,
    project_domain: Optional[str],
    token: Optional[str],
    base_url: str,
) -> None:
    """Upload a file as a report to Agent Berlin.

    FILE_PATH is the path to the file to upload.

    This uploads the file to Agent Berlin's storage and registers it
    so users can download it from the Agent Berlin UI.
    """
    # Resolve token and project_domain from config
    config = load_session_config()

    if not token:
        token = config.get("token")

    if not token:
        raise click.ClickException(
            "No API token found. Set AGENTBERLIN_TOKEN or configure session first."
        )

    if not project_domain:
        project_domain = config.get("project_domain")

    if not project_domain:
        raise click.ClickException(
            "No project domain found. Use --project-domain or configure session first."
        )

    source = Path(file_path)
    if not source.exists():
        raise click.ClickException(f"File not found: {file_path}")

    # Upload file to backend API
    headers = {"Authorization": f"Bearer {token}"}
    url = f"{base_url}/reports/upload"

    try:
        with open(source, "rb") as f:
            files = {"file": (source.name, f)}
            form_data = {"description": description, "project_domain": project_domain}
            resp = requests.post(
                url, headers=headers, files=files, data=form_data, timeout=120
            )
    except requests.RequestException as e:
        raise click.ClickException(f"Failed to connect to API: {e}")

    if resp.status_code == 401:
        raise click.ClickException("Authentication failed. Check your token.")
    if resp.status_code == 400:
        error_msg = resp.json().get("error", "Bad request")
        raise click.ClickException(f"Upload failed: {error_msg}")

    try:
        resp.raise_for_status()
    except requests.HTTPError as e:
        raise click.ClickException(f"API request failed: {e}")

    result = resp.json()
    click.echo(f"Report uploaded: {source.name}")
    click.echo(f"Description: {description}")
    if result.get("url"):
        click.echo(f"URL: {result['url']}")


def _generate_readme(data: dict, script_files: list[str], subagent_files: list[str]) -> str:
    """Generate README.md with workflow instruction, sub-agents, and config."""
    lines = [
        f"# {data.get('name', 'Workflow')}",
        "",
        "## Main Agent Instruction",
        "",
        data.get("instruction", ""),
        "",
    ]

    # Sub-agents section (reference files instead of inline content)
    subagents = data.get("subagents", [])
    if subagents:
        lines.append("## Sub-Agents")
        lines.append("")
        lines.append(
            "Sub-agents are separate instruction sets that help manage complex workflows. "
            "While the main agent can write and process data with Python scripts, "
            "sub-agents isolate specific tasks to prevent context pollution in the main process. "
            "Delegate work to sub-agents when their instructions apply."
        )
        lines.append("")
        for sa in subagents:
            name = sa["name"].replace(" ", "_").lower()
            lines.append(f"- **{sa['name']}** (`subagents/{name}.md`)")
        lines.append("")

    # Scripts section (just list them, code is in separate files)
    if script_files:
        lines.append("## Scripts")
        lines.append("")
        for script in data.get("scripts", []):
            name = script["name"].replace(" ", "_").lower()
            desc = script.get("description", "")
            lines.append(f"- **{script['name']}** (`scripts/{name}.py`): {desc}")
        lines.append("")

    # Configuration section
    config: dict = {}
    inputs = data.get("inputs", [])
    if inputs:
        config["inputs"] = inputs

    built_in_tools = data.get("built_in_tools", [])
    if built_in_tools:
        config["built_in_tools"] = built_in_tools

    if config:
        lines.append("## Configuration")
        lines.append("")
        lines.append("```json")
        lines.append(json.dumps(config, indent=2))
        lines.append("```")

    return "\n".join(lines)


if __name__ == "__main__":
    main()
