"""Unified control panel for P.I.G. Farm."""

from collections.abc import Callable
from dataclasses import dataclass
from pathlib import Path
from typing import Literal

from textual.app import ComposeResult
from textual.containers import Horizontal, Vertical
from textual.reactive import reactive
from textual.widgets import (
    Button,
    Checkbox,
    Input,
    Label,
    OptionList,
    RadioButton,
    RadioSet,
)
from textual.widgets.option_list import Option


@dataclass
class CleaveParams:
    """Parameters for Cleave execution."""

    parallel: bool = True
    dry_run: bool = False
    max_depth: int = 3
    model: Literal["sonnet", "opus", "haiku"] = "opus"
    selected_calf: Path | None = None


class ControlPanel(Vertical):
    """Unified control panel with file list and cleave parameters.

    Combines file selection (Slop Trough) with execution controls (Cleaver).

    Interface:
        get_params() -> CleaveParams - Get current execution parameters
        refresh_files() - Refresh the file list
        on_file_selected: Callable[[Path], None] - File selection callback
        on_calf_raises: Callable[[], None] - Start interrogation callback
        on_cleave: Callable[[CleaveParams], None] - Execute cleave callback
    """

    DEFAULT_CSS = """
    ControlPanel {
        height: 100%;
        padding: 1;
    }

    ControlPanel OptionList {
        height: auto;
        max-height: 8;
        margin-bottom: 1;
        border: solid $panel;
    }

    ControlPanel .options-row {
        layout: horizontal;
        height: auto;
        margin-bottom: 1;
    }

    ControlPanel .options-row Checkbox {
        width: auto;
        margin-right: 2;
    }

    ControlPanel .depth-row {
        layout: horizontal;
        height: auto;
        margin-bottom: 1;
    }

    ControlPanel .depth-row Label {
        width: auto;
        margin-right: 1;
    }

    ControlPanel .depth-row Input {
        width: 4;
    }

    ControlPanel .model-row {
        layout: horizontal;
        height: auto;
        margin-bottom: 1;
    }

    ControlPanel .model-row Label {
        width: auto;
        margin-right: 1;
    }

    ControlPanel .model-row RadioSet {
        layout: horizontal;
        height: auto;
        width: 1fr;
    }

    ControlPanel .model-row RadioButton {
        width: auto;
        margin-right: 1;
    }

    ControlPanel Button {
        width: 100%;
        margin-bottom: 1;
    }

    ControlPanel #cleave-button {
        margin-bottom: 0;
    }
    """

    # Directory to scan for .calf files
    directory: reactive[Path | None] = reactive(None)

    # Currently selected file
    selected_file: reactive[Path | None] = reactive(None)

    # Callbacks
    # on_calf_workflow receives (mode, selected_file) where mode is "raise" or "fatten"
    on_file_selected: Callable[[Path], None] | None = None
    on_calf_workflow: Callable[[str, Path | None], None] | None = None
    on_cleave: Callable[[CleaveParams], None] | None = None

    def compose(self) -> ComposeResult:
        """Compose the unified control panel."""
        # File list
        yield OptionList(id="calf-list")

        # Workflow button
        yield Button("Raise a Calf", id="calf-raises-button", variant="success")

        # Options row: checkboxes side by side
        with Horizontal(classes="options-row"):
            yield Checkbox("Parallel", id="parallel-check", value=True)
            yield Checkbox("Dry run", id="dry-run-check", value=False)

        # Depth row
        with Horizontal(classes="depth-row"):
            yield Label("Depth:")
            yield Input("3", id="max-depth-input", type="integer", max_length=2)

        # Model row
        with Horizontal(classes="model-row"):
            yield Label("Model:")
            with RadioSet(id="model-radio"):
                yield RadioButton("S", id="model-sonnet")
                yield RadioButton("O", id="model-opus", value=True)
                yield RadioButton("H", id="model-haiku")

        # Execute button
        yield Button("CLEAVE", id="cleave-button", variant="primary")

    def on_mount(self) -> None:
        """Initialize with current directory if set."""
        if self.directory:
            self.refresh_files()

    def watch_directory(self, value: Path | None) -> None:
        """Refresh file list when directory changes."""
        if value is not None and self.is_mounted:
            self.refresh_files()

    def watch_selected_file(self, value: Path | None) -> None:
        """Update button label when selection changes."""
        if not self.is_mounted:
            return
        button = self.query_one("#calf-raises-button", Button)
        if value is not None:
            button.label = "Fatten Calf"
        else:
            button.label = "Raise a Calf"

    def on_option_list_option_selected(self, event: OptionList.OptionSelected) -> None:
        """Handle file selection."""
        if event.option.id:
            path = Path(event.option.id)
            self.selected_file = path

            if self.on_file_selected is not None:
                self.on_file_selected(path)

    def on_button_pressed(self, event: Button.Pressed) -> None:
        """Handle button presses."""
        if event.button.id == "calf-raises-button" and self.on_calf_workflow is not None:
            # Determine mode based on selection
            mode = "fatten" if self.selected_file is not None else "raise"
            self.on_calf_workflow(mode, self.selected_file)
        elif event.button.id == "cleave-button" and self.on_cleave is not None:
            self.on_cleave(self.get_params())

    def refresh_files(self) -> None:
        """Refresh the file list from the directory."""
        option_list = self.query_one("#calf-list", OptionList)
        option_list.clear_options()

        if self.directory is None or not self.directory.exists():
            return

        calf_files = sorted(self.directory.glob("*.calf"))

        for calf_file in calf_files:
            option_list.add_option(Option(calf_file.name, id=str(calf_file)))

    def get_files(self) -> list[Path]:
        """Get list of .calf files in the directory."""
        if self.directory is None or not self.directory.exists():
            return []
        return sorted(self.directory.glob("*.calf"))

    def get_params(self) -> CleaveParams:
        """Get current parameter values."""
        parallel = self.query_one("#parallel-check", Checkbox).value
        dry_run = self.query_one("#dry-run-check", Checkbox).value

        depth_input = self.query_one("#max-depth-input", Input)
        try:
            max_depth = int(depth_input.value)
        except ValueError:
            max_depth = 3

        radio_set = self.query_one("#model-radio", RadioSet)
        model: Literal["sonnet", "opus", "haiku"] = "opus"
        if radio_set.pressed_button:
            button_id = radio_set.pressed_button.id
            if button_id == "model-sonnet":
                model = "sonnet"
            elif button_id == "model-haiku":
                model = "haiku"

        return CleaveParams(
            parallel=parallel,
            dry_run=dry_run,
            max_depth=max_depth,
            model=model,
            selected_calf=self.selected_file,
        )
