"""Management commands for workflows."""

from __future__ import annotations
import typer
from orcheo_sdk.cli.errors import CLIError
from orcheo_sdk.cli.output import print_json, render_json
from orcheo_sdk.cli.utils import load_with_cache
from orcheo_sdk.cli.workflow.app import (
    ActorOption,
    EntrypointOption,
    FilePathArgument,
    ForceOption,
    FormatOption,
    OutputPathOption,
    RunnableConfigFileOption,
    RunnableConfigOption,
    VersionOption,
    WorkflowIdArgument,
    WorkflowIdOption,
    WorkflowNameOption,
    _state,
    workflow_app,
)
from orcheo_sdk.cli.workflow.inputs import (
    _cache_notice,
    _resolve_runnable_config,
    _validate_local_path,
)
from orcheo_sdk.services import (
    delete_workflow_data,
    download_workflow_data,
    sync_cron_schedule_if_changed,
    update_workflow_data,
    upload_workflow_data,
)


@workflow_app.command("delete")
def delete_workflow(
    ctx: typer.Context,
    workflow_id: WorkflowIdArgument,
    force: ForceOption = False,
) -> None:
    """Delete a workflow by ID."""
    state = _state(ctx)
    if state.settings.offline:
        raise CLIError("Deleting workflows requires network connectivity.")

    if not state.human and not force:
        print_json({"error": "Use --force to confirm deletion in machine mode."})
        raise typer.Exit(code=1)
    if not force:
        typer.confirm(
            f"Are you sure you want to delete workflow '{workflow_id}'?",
            abort=True,
        )

    result = delete_workflow_data(state.client, workflow_id)
    if not state.human:
        print_json(result)
        return
    raw_message = result.get("message", "")
    if raw_message and "deleted successfully" in raw_message.lower():
        success_message = raw_message
    else:
        success_message = f"Workflow '{workflow_id}' deleted successfully."
    state.console.print(f"[green]{success_message}[/green]")


@workflow_app.command("upload")
def upload_workflow(
    ctx: typer.Context,
    file_path: FilePathArgument,
    workflow_id: WorkflowIdOption = None,
    entrypoint: EntrypointOption = None,
    workflow_name: WorkflowNameOption = None,
    config: RunnableConfigOption = None,
    config_file: RunnableConfigFileOption = None,
) -> None:
    """Upload a workflow from a Python or JSON file."""
    state = _state(ctx)
    if state.settings.offline:
        raise CLIError("Uploading workflows requires network connectivity.")

    runnable_config = _resolve_runnable_config(config, config_file)
    result = upload_workflow_data(
        state.client,
        file_path,
        workflow_id=workflow_id,
        workflow_name=workflow_name,
        entrypoint=entrypoint,
        runnable_config=runnable_config,
        console=state.console,
    )
    resolved_id = workflow_id or result.get("id")

    # Auto-update cron schedule if it was already registered and has changed.
    cron_sync: dict[str, str] | None = None
    if resolved_id:
        try:
            cron_sync = sync_cron_schedule_if_changed(state.client, resolved_id)
        except Exception:  # noqa: BLE001
            cron_sync = None

    if not state.human:
        if cron_sync and cron_sync.get("status") == "updated":
            result["cron_schedule"] = cron_sync
        print_json(result)
        return
    identifier = resolved_id or "workflow"
    action = "updated" if workflow_id else "uploaded"
    success_message = f"[green]Workflow '{identifier}' {action} successfully.[/green]"
    state.console.print(success_message)
    render_json(state.console, result, title="Workflow")
    if cron_sync and cron_sync.get("status") == "updated":
        state.console.print(f"[green]{cron_sync['message']}[/green]")
        render_json(state.console, cron_sync.get("config", {}), title="Cron trigger")


@workflow_app.command("update")
def update_workflow(
    ctx: typer.Context,
    workflow_id: WorkflowIdArgument,
    workflow_name: WorkflowNameOption = None,
    handle: str | None = typer.Option(
        None,
        "--handle",
        help="Update the workflow handle.",
    ),
    description: str | None = typer.Option(
        None,
        "--description",
        help="Update the workflow description.",
    ),
    actor: ActorOption = "cli",
) -> None:
    """Update workflow metadata."""
    state = _state(ctx)
    if state.settings.offline:
        raise CLIError("Updating workflows requires network connectivity.")
    if workflow_name is None and handle is None and description is None:
        raise CLIError("Provide at least one field to update.")

    result = update_workflow_data(
        state.client,
        workflow_id,
        name=workflow_name,
        handle=handle,
        description=description,
        actor=actor,
    )
    if not state.human:
        print_json(result)
        return

    state.console.print(
        f"[green]Workflow '{workflow_id}' updated successfully.[/green]"
    )
    render_json(state.console, result, title="Workflow")


@workflow_app.command("download")
def download_workflow(
    ctx: typer.Context,
    workflow_id: WorkflowIdArgument,
    output_path: OutputPathOption = None,
    format_type: FormatOption = "auto",
    version: VersionOption = None,
) -> None:
    """Download a workflow configuration to a file or stdout."""
    state = _state(ctx)
    version_suffix = f":{version}" if version else ""
    payload, from_cache, stale = load_with_cache(
        state,
        f"workflow:{workflow_id}:download:{format_type}{version_suffix}",
        lambda: download_workflow_data(
            state.client,
            workflow_id,
            output_path=None,
            format_type=format_type,
            target_version=version,
        ),
    )
    if from_cache:
        _cache_notice(state, f"workflow {workflow_id}", stale)

    content = payload["content"]

    if not state.human and not output_path:
        print_json(payload)
        return

    if output_path:
        output_file = _validate_local_path(
            output_path,
            description="output",
            must_exist=False,
            require_file=True,
        )
        output_file.write_text(content, encoding="utf-8")
        if not state.human:
            print_json({"status": "success", "path": str(output_path)})
            return
        state.console.print(f"[green]Workflow downloaded to '{output_path}'.[/green]")
    else:
        state.console.print(content)


__all__ = [
    "delete_workflow",
    "update_workflow",
    "upload_workflow",
    "download_workflow",
]
