"""Dash web application factory.

Creates the Dash app with all layout components and callbacks registered.
The AppState holds server-side data; Dash stores hold lightweight UI state.
"""

from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING

import dash
import dash_bootstrap_components as dbc

from impakt.channel.model import TestData
from impakt.template.library import TemplateLibrary
from impakt.web.callbacks import register_callbacks
from impakt.web.layout import build_layout
from impakt.web.state import AppState

if TYPE_CHECKING:
    from impakt.script.api import Session


def create_app(
    session_or_data: Session | TestData | None = None,
    template_names: list[str] | None = None,
    app_state: AppState | None = None,
) -> dash.Dash:
    """Create the Dash application.

    Args:
        session_or_data: A Session, TestData, or None (empty app).
        template_names: Available template names for the selector.
        app_state: Pre-configured AppState. If None, one is created.

    Returns:
        Configured Dash app ready to run.
    """
    # Build or use provided AppState
    if app_state is None:
        app_state = AppState()
        if session_or_data is not None:
            if hasattr(session_or_data, "data"):
                test_data: TestData = session_or_data.data  # type: ignore[union-attr]
            else:
                test_data = session_or_data  # type: ignore[assignment]

            # Create a LoadedTest from TestData directly
            from impakt.web.state import LoadedTest

            loaded = LoadedTest(test_data)
            app_state._tests[test_data.test_id] = loaded
            app_state._test_order.append(test_data.test_id)

    # Discover templates
    if template_names is None:
        try:
            lib = TemplateLibrary()
            template_names = lib.list()
        except Exception:
            template_names = []

    # Title
    title = "Impakt"
    if app_state.primary_test:
        title = f"Impakt — {app_state.primary_test.test_id}"

    app = dash.Dash(
        __name__,
        external_stylesheets=[dbc.themes.FLATLY],
        title=title,
        suppress_callback_exceptions=True,
        # Prevent browser from caching old layouts
        serve_locally=True,
        meta_tags=[
            {"http-equiv": "Cache-Control", "content": "no-cache, no-store, must-revalidate"},
            {"http-equiv": "Pragma", "content": "no-cache"},
            {"http-equiv": "Expires", "content": "0"},
        ],
    )

    app.layout = build_layout(app_state, template_names)
    register_callbacks(app, app_state)

    return app


def serve(
    session_or_data: Session | TestData | None = None,
    template: str | None = None,
    port: int = 8050,
    debug: bool = False,
) -> None:
    """Convenience function to create and run the web UI.

    Args:
        session_or_data: Session or TestData to visualize, or None for empty app.
        template: Template name to pre-apply.
        port: Server port.
        debug: Enable Dash debug mode.
    """
    if template and session_or_data and hasattr(session_or_data, "apply_template"):
        session_or_data.apply_template(template)  # type: ignore[union-attr]

    app = create_app(session_or_data)
    print(f"Impakt running at http://localhost:{port}")
    app.run(debug=debug, port=port)
