"""Dialog CLI commands — detect and interact with system dialogs.

Phase 4.5.1 + 4.5.2: Dialog Detection & Interaction.

Provides commands to detect active dialog windows (message boxes, file pickers,
confirmations) and interact with them (accept, dismiss, click buttons, type text).

Examples:
    naturo dialog detect                     # List active dialogs
    naturo dialog detect --app notepad       # Filter by app
    naturo dialog accept                     # Click OK/Yes/Open
    naturo dialog dismiss                    # Click Cancel/No/Close
    naturo dialog click-button "Save"        # Click specific button
    naturo dialog type "hello.txt"           # Type in input field
    naturo dialog type "hello.txt" --accept  # Type then click OK
"""

from __future__ import annotations

import json as _json
import sys

import click

from naturo.cli.error_helpers import emit_error, emit_exception_error


@click.group()
def dialog():
    """Detect and interact with system dialogs.

    Handles message boxes, file pickers, confirmation prompts, and other
    modal dialog windows. Essential for AI agent automation when dialogs
    block the main workflow.

    Examples:
        naturo dialog detect                   # List active dialogs
        naturo dialog detect --app notepad     # Filter by app
        naturo dialog accept                   # Click OK/Yes/Open
        naturo dialog dismiss                  # Click Cancel/No/Close
        naturo dialog click-button "Save"      # Click a specific button
        naturo dialog type "hello.txt"         # Type into dialog input
    """
    pass


@dialog.command()
@click.option("--app", help="Filter by owner application name")
@click.option("--hwnd", type=int, help="Filter by dialog window handle")
@click.option("--json", "-j", "json_output", is_flag=True, help="JSON output")
def detect(app, hwnd, json_output):
    """Detect active dialog windows.

    Scans for system dialogs including message boxes, file pickers,
    confirmation prompts, and application-specific modal dialogs.

    Returns dialog type, title, message, available buttons, and
    whether an input field is present.

    Examples:
        naturo dialog detect                   # List all dialogs
        naturo dialog detect --app notepad     # Filter by app
        naturo dialog detect --json            # JSON output
    """
    from naturo.backends.base import get_backend
    from naturo.errors import NaturoError

    try:
        backend = get_backend()
        dialogs = backend.detect_dialogs(app=app, hwnd=hwnd)

        if json_output:
            result = {
                "success": True,
                "dialogs": [d.to_dict() for d in dialogs],
                "count": len(dialogs),
            }
            click.echo(_json.dumps(result))
        else:
            if not dialogs:
                click.echo("No dialogs detected.")
            else:
                for i, d in enumerate(dialogs):
                    if i > 0:
                        click.echo()
                    click.echo(f"Dialog: {d.title}")
                    click.echo(f"  Type: {d.dialog_type.value}")
                    click.echo(f"  HWND: {d.hwnd}")
                    if d.message:
                        click.echo(f"  Message: {d.message}")
                    if d.buttons:
                        btn_names = ", ".join(b.name for b in d.buttons)
                        click.echo(f"  Buttons: {btn_names}")
                    if d.has_input:
                        click.echo(f"  Input: {d.input_value!r}")
                    if d.owner_app:
                        click.echo(f"  Owner: {d.owner_app}")

    except NaturoError as e:
        emit_exception_error(e, json_output)
    except Exception as e:
        emit_exception_error(e, json_output, fallback_code="UNKNOWN_ERROR")


@dialog.command()
@click.option("--app", help="Owner application name filter")
@click.option("--hwnd", type=int, help="Specific dialog window handle")
@click.option("--json", "-j", "json_output", is_flag=True, help="JSON output")
def accept(app, hwnd, json_output):
    """Accept (confirm) the active dialog.

    Clicks the first accept-type button found: OK, Yes, Open, Save,
    Continue, Apply, Print, 确定, 是, etc.

    Examples:
        naturo dialog accept                   # Accept first dialog
        naturo dialog accept --app notepad     # Accept notepad's dialog
        naturo dialog accept --json            # JSON output
    """
    from naturo.backends.base import get_backend
    from naturo.errors import NaturoError
    from naturo.dialog import _ACCEPT_BUTTONS

    try:
        backend = get_backend()
        dialogs = backend.detect_dialogs(app=app, hwnd=hwnd)
        if not dialogs:
            emit_error("DIALOG_NOT_FOUND", "No dialog detected", json_output)

        target_dialog = dialogs[0]
        if hwnd:
            target_dialog = next((d for d in dialogs if d.hwnd == hwnd), dialogs[0])

        # Find the accept button
        accept_btn = None
        for btn in target_dialog.buttons:
            if btn.name.lower() in _ACCEPT_BUTTONS or btn.is_default:
                accept_btn = btn
                break

        if not accept_btn:
            available = ", ".join(b.name for b in target_dialog.buttons)
            emit_error(
                "ELEMENT_NOT_FOUND",
                f"No accept button found in dialog. Available: [{available}]",
                json_output,
            )

        backend.click(x=accept_btn.x, y=accept_btn.y)

        if json_output:
            click.echo(_json.dumps({
                "success": True,
                "dialog_title": target_dialog.title,
                "button_clicked": accept_btn.name,
                "dialog_hwnd": target_dialog.hwnd,
            }))
        else:
            click.echo(f"Accepted dialog '{target_dialog.title}' (clicked '{accept_btn.name}')")

    except NaturoError as e:
        emit_exception_error(e, json_output)
    except SystemExit:
        raise
    except Exception as e:
        emit_exception_error(e, json_output, fallback_code="UNKNOWN_ERROR")


@dialog.command()
@click.option("--app", help="Owner application name filter")
@click.option("--hwnd", type=int, help="Specific dialog window handle")
@click.option("--json", "-j", "json_output", is_flag=True, help="JSON output")
def dismiss(app, hwnd, json_output):
    """Dismiss (cancel) the active dialog.

    Clicks the first dismiss-type button found: Cancel, No, Close,
    Abort, 取消, 否, etc.

    Examples:
        naturo dialog dismiss                  # Dismiss first dialog
        naturo dialog dismiss --app notepad    # Dismiss notepad's dialog
        naturo dialog dismiss --json           # JSON output
    """
    from naturo.backends.base import get_backend
    from naturo.errors import NaturoError
    from naturo.dialog import _DISMISS_BUTTONS

    try:
        backend = get_backend()
        dialogs = backend.detect_dialogs(app=app, hwnd=hwnd)
        if not dialogs:
            emit_error("DIALOG_NOT_FOUND", "No dialog detected", json_output)

        target_dialog = dialogs[0]
        if hwnd:
            target_dialog = next((d for d in dialogs if d.hwnd == hwnd), dialogs[0])

        # Find the dismiss button
        dismiss_btn = None
        for btn in target_dialog.buttons:
            if btn.name.lower() in _DISMISS_BUTTONS or btn.is_cancel:
                dismiss_btn = btn
                break

        if not dismiss_btn:
            available = ", ".join(b.name for b in target_dialog.buttons)
            emit_error(
                "ELEMENT_NOT_FOUND",
                f"No dismiss button found in dialog. Available: [{available}]",
                json_output,
            )

        backend.click(x=dismiss_btn.x, y=dismiss_btn.y)

        if json_output:
            click.echo(_json.dumps({
                "success": True,
                "dialog_title": target_dialog.title,
                "button_clicked": dismiss_btn.name,
                "dialog_hwnd": target_dialog.hwnd,
            }))
        else:
            click.echo(f"Dismissed dialog '{target_dialog.title}' (clicked '{dismiss_btn.name}')")

    except NaturoError as e:
        emit_exception_error(e, json_output)
    except SystemExit:
        raise
    except Exception as e:
        emit_exception_error(e, json_output, fallback_code="UNKNOWN_ERROR")


@dialog.command("click-button")
@click.argument("button")
@click.option("--app", help="Owner application name filter")
@click.option("--hwnd", type=int, help="Specific dialog window handle")
@click.option("--json", "-j", "json_output", is_flag=True, help="JSON output")
def click_button(button, app, hwnd, json_output):
    """Click a specific button in the active dialog.

    Finds a button by name (case-insensitive, supports partial match)
    and clicks it.

    Examples:
        naturo dialog click-button "Save"         # Click Save
        naturo dialog click-button "Don't Save"   # Click Don't Save
        naturo dialog click-button "Retry"         # Click Retry
    """
    from naturo.backends.base import get_backend
    from naturo.errors import NaturoError

    if not button.strip():
        emit_error("INVALID_INPUT", "Button name cannot be empty", json_output)

    try:
        backend = get_backend()
        result = backend.dialog_click_button(button=button, app=app, hwnd=hwnd)

        if json_output:
            click.echo(_json.dumps({"success": True, **result}))
        else:
            click.echo(
                f"Clicked '{result['button_clicked']}' in dialog '{result['dialog_title']}'"
            )

    except NaturoError as e:
        emit_exception_error(e, json_output)
    except SystemExit:
        raise
    except Exception as e:
        emit_exception_error(e, json_output, fallback_code="UNKNOWN_ERROR")


@dialog.command("type")
@click.argument("text")
@click.option("--accept", "do_accept", is_flag=True,
              help="Click OK/Accept after typing")
@click.option("--app", help="Owner application name filter")
@click.option("--hwnd", type=int, help="Specific dialog window handle")
@click.option("--json", "-j", "json_output", is_flag=True, help="JSON output")
def dialog_type(text, do_accept, app, hwnd, json_output):
    """Type text into a dialog's input field.

    Finds the dialog's input/edit control, clears it, and types
    the provided text. With --accept, also clicks the OK button.

    Examples:
        naturo dialog type "hello.txt"            # Type filename
        naturo dialog type "hello.txt" --accept   # Type then click OK
        naturo dialog type "C:\\Users" --app notepad
    """
    from naturo.backends.base import get_backend
    from naturo.errors import NaturoError
    from naturo.dialog import _ACCEPT_BUTTONS

    if not text:
        emit_error("INVALID_INPUT", "Text cannot be empty", json_output)

    try:
        backend = get_backend()
        result = backend.dialog_set_input(text=text, app=app, hwnd=hwnd)

        accepted_button = None
        if do_accept:
            dialogs = backend.detect_dialogs(app=app, hwnd=hwnd)
            if dialogs:
                for btn in dialogs[0].buttons:
                    if btn.name.lower() in _ACCEPT_BUTTONS or btn.is_default:
                        backend.click(x=btn.x, y=btn.y)
                        accepted_button = btn.name
                        break

        if json_output:
            out = {"success": True, **result}
            if accepted_button:
                out["accepted_with"] = accepted_button
            click.echo(_json.dumps(out))
        else:
            msg = f"Typed '{text}' in dialog '{result['dialog_title']}'"
            if accepted_button:
                msg += f" (accepted with '{accepted_button}')"
            click.echo(msg)

    except NaturoError as e:
        emit_exception_error(e, json_output)
    except SystemExit:
        raise
    except Exception as e:
        emit_exception_error(e, json_output, fallback_code="UNKNOWN_ERROR")
