"""Interactive TUI forms for launching MixerSystem workflows.

Uses the textual library to present a form for each workflow.
Fields are defined as data, not separate classes per workflow.
The form collects values, builds CLI args, and runs the workflow
via subprocess.
"""

from __future__ import annotations

import json
import secrets
import subprocess
import sys
from pathlib import Path
from typing import Any

from textual.app import App, ComposeResult
from textual.binding import Binding
from textual.containers import Horizontal, VerticalScroll
from textual.containers import Vertical
from textual.widgets import (
    Button,
    Footer,
    Header,
    Input,
    Label,
    Select,
    Static,
    Switch,
    TextArea,
)


# ── Field definitions ──────────────────────────────────────────────

TASK_FIELDS: list[dict[str, Any]] = [
    {
        "name": "work_folder",
        "type": "text",
        "label": "Work Folder",
        "placeholder": "Last used or auto-generated if empty",
    },
    {
        "name": "description",
        "type": "text",
        "label": "Description",
        "placeholder": "Only for new tasks",
    },
    {
        "name": "modules",
        "type": "text",
        "label": "Modules",
        "placeholder": "comma-separated or 'all'",
    },
    {
        "name": "instructions",
        "type": "textarea",
        "label": "Instructions",
        "placeholder": "Optional guidance for the builder",
    },
    {
        "name": "sync",
        "type": "switch",
        "label": "Sync to Linear",
        "description": "Local task: creates on Linear.\nLinear task: overrides existing issue.",
    },
    {
        "name": "mock",
        "type": "switch",
        "label": "Mock mode",
        "description": "Runs with a small model for quick testing.",
    },
]

_PROVIDER_OPTIONS = [
    ("Claude", "claude"),
    ("Gemini", "gemini"),
    ("Codex", "codex"),
    ("Random", "random"),
]

PLAN_FIELDS: list[dict[str, Any]] = [
    {
        "name": "work_folder",
        "type": "text",
        "label": "Work Folder",
        "placeholder": "Last used or auto-generated if empty",
    },
    {
        "name": "plan_builder_provider",
        "type": "select",
        "label": "Provider",
        "options": _PROVIDER_OPTIONS,
        "default": "claude",
    },
    {
        "name": "branch_count",
        "type": "text",
        "label": "Branches",
        "default": "1",
        "placeholder": "Number of parallel drafts (minimum 1)",
    },
    {
        "name": "max_revisions",
        "type": "text",
        "label": "Max Revisions",
        "default": "2",
        "placeholder": "0 to skip review",
    },
    {
        "name": "instructions",
        "type": "textarea",
        "label": "Instructions",
        "placeholder": "Optional guidance for the builder",
    },
    {
        "name": "mock",
        "type": "switch",
        "label": "Mock mode",
        "description": "Runs with a small model for quick testing.",
    },
]

WORK_FIELDS: list[dict[str, Any]] = [
    {
        "name": "work_folder",
        "type": "text",
        "label": "Work Folder",
        "placeholder": "Last used or auto-generated if empty",
    },
    {
        "name": "work_builder_provider",
        "type": "select",
        "label": "Provider",
        "options": _PROVIDER_OPTIONS,
        "default": "claude",
    },
    {
        "name": "max_test_iterations",
        "type": "text",
        "label": "Max Tests",
        "default": "5",
        "placeholder": "0 to skip testing",
    },
    {
        "name": "instructions",
        "type": "textarea",
        "label": "Instructions",
        "placeholder": "Optional guidance for the builder",
    },
    {
        "name": "mock",
        "type": "switch",
        "label": "Mock mode",
        "description": "Runs with a small model for quick testing.",
    },
]

UPDATE_FIELDS: list[dict[str, Any]] = [
    {
        "name": "work_folder",
        "type": "text",
        "label": "Work Folder",
        "placeholder": "Last used or auto-generated if empty",
    },
    {
        "name": "instructions",
        "type": "textarea",
        "label": "Instructions",
        "placeholder": "Optional guidance for the builder",
    },
    {
        "name": "mock",
        "type": "switch",
        "label": "Mock mode",
        "description": "Runs with a small model for quick testing.",
    },
]

UPGRADE_FIELDS: list[dict[str, Any]] = [
    {
        "name": "work_folder",
        "type": "text",
        "label": "Work Folder",
        "placeholder": "Last used or auto-generated if empty",
    },
    {
        "name": "instructions",
        "type": "textarea",
        "label": "Instructions",
        "placeholder": "Optional guidance for the builder",
    },
    {
        "name": "mock",
        "type": "switch",
        "label": "Mock mode",
        "description": "Runs with a small model for quick testing.",
    },
]

WORKFLOW_FORMS: dict[str, dict[str, Any]] = {
    "task":    {"title": "Create Task",    "fields": TASK_FIELDS},
    "plan":    {"title": "Create Plan",    "fields": PLAN_FIELDS},
    "work":    {"title": "Create Work",    "fields": WORK_FIELDS},
    "update":  {"title": "Create Update",  "fields": UPDATE_FIELDS},
    "upgrade": {"title": "Create Upgrade", "fields": UPGRADE_FIELDS},
}


# ── Form App ───────────────────────────────────────────────────────

class WorkflowFormApp(App[dict[str, Any] | None]):
    """Generic data-driven workflow form."""

    TITLE = "MixerSystem"
    BINDINGS = [
        Binding("escape", "cancel", "Cancel"),
        Binding("ctrl+s", "submit", "Run"),
    ]

    CSS = """
    Screen {
        align: center middle;
    }
    #form-container {
        width: 80;
        max-height: 90%;
        border: solid $accent;
        padding: 1 2;
    }
    .field-row {
        height: auto;
        margin-top: 1;
    }
    .field-label {
        width: 16;
        height: 3;
        content-align-vertical: middle;
        text-style: bold;
    }
    .field-input {
        width: 1fr;
    }
    .switch-group {
        height: auto;
        margin-top: 1;
    }
    .switch-row {
        height: auto;
    }
    .switch-label {
        width: auto;
        height: 3;
        content-align-vertical: middle;
        text-style: bold;
        margin-left: 1;
    }
    .switch-description {
        color: $text-muted;
        margin-left: 5;
    }
    TextArea {
        height: 6;
    }
    #button-bar {
        margin-top: 1;
        height: auto;
        align: center middle;
    }
    Button {
        margin: 0 1;
    }
    #error-label {
        color: $error;
        margin-top: 1;
        display: none;
    }
    """

    def __init__(self, workflow_name: str, form_config: dict[str, Any]) -> None:
        super().__init__()
        self.workflow_name = workflow_name
        self.form_config = form_config
        self.sub_title = form_config["title"]

    def compose(self) -> ComposeResult:
        yield Header()
        with VerticalScroll(id="form-container"):
            for field in self.form_config["fields"]:
                yield from self._compose_field(field)
            yield Static("", id="error-label")
            with Horizontal(id="button-bar"):
                yield Button("Run", variant="success", id="btn-run")
                yield Button("Cancel", variant="error", id="btn-cancel")
        yield Footer()

    def _compose_field(self, field: dict[str, Any]) -> ComposeResult:
        ftype = field.get("type", "text")
        name = field["name"]
        label_text = field.get("label", name)
        required = field.get("required", False)

        if required:
            label_text = f"{label_text} *"

        if ftype == "switch":
            description = field.get("description", "")
            with Vertical(classes="switch-group"):
                with Horizontal(classes="switch-row"):
                    yield Switch(
                        value=bool(field.get("default", False)),
                        id=f"field-{name}",
                    )
                    yield Label(label_text, classes="switch-label")
                if description:
                    yield Static(description, classes="switch-description")
        elif ftype == "select":
            with Horizontal(classes="field-row"):
                yield Label(label_text, classes="field-label")
                yield Select(
                    options=field.get("options", []),
                    value=field.get("default", Select.BLANK),
                    id=f"field-{name}",
                    classes="field-input",
                )
        elif ftype == "textarea":
            with Horizontal(classes="field-row"):
                yield Label(label_text, classes="field-label")
                yield TextArea(
                    field.get("default", ""),
                    id=f"field-{name}",
                    classes="field-input",
                )
        else:
            with Horizontal(classes="field-row"):
                yield Label(label_text, classes="field-label")
                yield Input(
                    value=str(field.get("default", "")),
                    placeholder=field.get("placeholder", ""),
                    id=f"field-{name}",
                    classes="field-input",
                )

    def _collect(self) -> dict[str, Any]:
        data: dict[str, Any] = {}
        for field in self.form_config["fields"]:
            name = field["name"]
            widget_id = f"field-{name}"
            ftype = field.get("type", "text")

            if ftype == "text":
                data[name] = self.query_one(f"#{widget_id}", Input).value.strip()
            elif ftype == "textarea":
                data[name] = self.query_one(f"#{widget_id}", TextArea).text.strip()
            elif ftype == "switch":
                data[name] = self.query_one(f"#{widget_id}", Switch).value
            elif ftype == "select":
                val = self.query_one(f"#{widget_id}", Select).value
                data[name] = val if val != Select.BLANK else ""
        return data

    def _validate(self, data: dict[str, Any]) -> str | None:
        for field in self.form_config["fields"]:
            if field.get("required", False):
                value = data.get(field["name"], "")
                if not value:
                    return f"{field.get('label', field['name'])} is required."
        return None

    def action_submit(self) -> None:
        self._do_submit()

    def action_cancel(self) -> None:
        self.exit(None)

    def on_button_pressed(self, event: Button.Pressed) -> None:
        if event.button.id == "btn-run":
            self._do_submit()
        elif event.button.id == "btn-cancel":
            self.exit(None)

    def _do_submit(self) -> None:
        data = self._collect()
        error = self._validate(data)
        error_label = self.query_one("#error-label", Static)
        if error:
            error_label.update(error)
            error_label.styles.display = "block"
            return
        error_label.styles.display = "none"
        self.exit(data)


# ── CLI bridge ─────────────────────────────────────────────────────

_SETTINGS_FILE = Path(".mixer/settings.json")


def _read_last_work_folder() -> str | None:
    try:
        data = json.loads(_SETTINGS_FILE.read_text())
        return data.get("last_work_folder") or None
    except (FileNotFoundError, json.JSONDecodeError, OSError):
        return None


def _save_last_work_folder(work_folder: str) -> None:
    try:
        data = json.loads(_SETTINGS_FILE.read_text())
    except (FileNotFoundError, json.JSONDecodeError, OSError):
        return
    data["last_work_folder"] = work_folder
    _SETTINGS_FILE.write_text(json.dumps(data, indent=2) + "\n")


def _build_cli_args(workflow_name: str,
                    data: dict[str, Any],
                    fields: list[dict[str, Any]]) -> list[str]:
    args = [
        sys.executable, "-m", "mixersystem",
        "run", workflow_name,
    ]
    for field in fields:
        name = field["name"]
        ftype = field.get("type", "text")
        value = data.get(name)

        if ftype == "switch":
            if value:
                args.append(f"--{name}=true")
        elif value:
            args.append(f"--{name}={value}")
    return args


def launch_tui(workflow_name: str) -> int:
    """Launch the TUI form for a workflow, then run the command."""
    form_config = WORKFLOW_FORMS.get(workflow_name)
    if not form_config:
        print(f"No interactive form defined for '{workflow_name}'.")
        print(f"Available: {', '.join(sorted(WORKFLOW_FORMS.keys()))}")
        return 1

    # Prefill work_folder from last run if available.
    last_wf = _read_last_work_folder()
    if last_wf:
        fields_copy = []
        for field in form_config["fields"]:
            if field["name"] == "work_folder":
                field = {**field, "default": last_wf}
            fields_copy.append(field)
        form_config = {**form_config, "fields": fields_copy}

    app = WorkflowFormApp(workflow_name, form_config)
    data = app.run()

    if data is None:
        print("Cancelled.")
        return 0

    work_folder = data.get("work_folder", "")
    if not work_folder:
        work_folder = f"tasks/local-{secrets.token_hex(2)}"
        data["work_folder"] = work_folder
    _save_last_work_folder(work_folder)

    args = _build_cli_args(workflow_name, data, form_config["fields"])
    print(f"\n> {' '.join(args)}\n")

    result = subprocess.run(args)
    return result.returncode
