"""Template management callbacks.

Handles:
- Apply template (resolve patterns, set channels, set transforms)
- Save current view as template
- Delete template
- Session auto-save
"""

from __future__ import annotations

from typing import Any

import dash
from dash import Input, Output, State, html, no_update
from dash.exceptions import PreventUpdate

from impakt.web.state import AppState


def register_template_callbacks(app: dash.Dash, app_state: AppState) -> None:
    """Register template management callbacks."""

    @app.callback(
        [
            Output("selected-channels-store", "data", allow_duplicate=True),
            Output("cfc-select", "value", allow_duplicate=True),
            Output("template-status", "children", allow_duplicate=True),
        ],
        [Input("apply-template-btn", "n_clicks")],
        [State("template-library-select", "value")],
        prevent_initial_call=True,
    )
    def apply_template(
        n_clicks: int | None,
        template_name: str | None,
    ) -> tuple[list[str], str, Any]:
        if not n_clicks or not template_name:
            raise PreventUpdate

        try:
            resolved_keys, transforms = app_state.apply_template(template_name)
            cfc = transforms.get("cfc", "none")

            return (
                resolved_keys,
                cfc,
                html.Div(
                    f"Applied '{template_name}' — {len(resolved_keys)} channels",
                    className="text-success small",
                ),
            )
        except FileNotFoundError:
            return (
                no_update,
                no_update,
                html.Div(f"Template '{template_name}' not found", className="text-danger small"),
            )
        except Exception as e:
            return (
                no_update,
                no_update,
                html.Div(f"Error: {e}", className="text-danger small"),
            )

    @app.callback(
        Output("template-status", "children"),
        [Input("save-template-btn", "n_clicks")],
        [
            State("save-template-name", "value"),
            State("save-template-desc", "value"),
            State("selected-channels-store", "data"),
            State("cfc-select", "value"),
            State("cursor-x1", "value"),
            State("cursor-x2", "value"),
            State("protocol-select", "value"),
        ],
        prevent_initial_call=True,
    )
    def save_template(
        n_clicks: int | None,
        name: str | None,
        description: str | None,
        selected_keys: list[str] | None,
        cfc_value: str,
        x1: float | None,
        x2: float | None,
        protocol: str,
    ) -> Any:
        if not n_clicks:
            raise PreventUpdate

        if not name or not name.strip():
            return html.Div("Enter a template name", className="text-warning small")

        if not selected_keys:
            return html.Div("No channels selected to save", className="text-warning small")

        try:
            template = app_state.save_as_template(
                name=name.strip(),
                description=(description or "").strip(),
                selected_keys=selected_keys,
                cfc_value=cfc_value,
                x1=x1,
                x2=x2,
                protocol=protocol,
            )
            return html.Div(
                f"Saved '{template.name}' ({len(selected_keys)} channels)",
                className="text-success small",
            )
        except Exception as e:
            return html.Div(f"Save failed: {e}", className="text-danger small")

    @app.callback(
        Output("template-status", "children", allow_duplicate=True),
        [Input("delete-template-btn", "n_clicks")],
        [State("template-library-select", "value")],
        prevent_initial_call=True,
    )
    def delete_template(n_clicks: int | None, template_name: str | None) -> Any:
        if not n_clicks or not template_name:
            raise PreventUpdate

        if app_state.template_library.delete(template_name):
            return html.Div(f"Deleted '{template_name}'", className="text-success small")
        else:
            return html.Div(f"Template '{template_name}' not found", className="text-warning small")

    # Session auto-save: save on channel selection or CFC change
    @app.callback(
        Output("session-store", "data"),
        [
            Input("selected-channels-store", "data"),
            Input("cfc-select", "value"),
        ],
        prevent_initial_call=True,
    )
    def auto_save_session(
        selected_keys: list[str] | None,
        cfc_value: str,
    ) -> dict[str, Any]:
        if not selected_keys:
            selected_keys = []

        try:
            app_state.save_session(selected_keys, cfc_value)
        except Exception:
            pass  # Don't let save failures break the UI

        return {"saved": True, "channels": len(selected_keys)}
