"""Export callbacks.

Handles:
- Plot image export (PNG, SVG, PDF)
- Data CSV export
- Protocol report generation
"""

from __future__ import annotations

import io
import tempfile
from typing import Any

import dash
import numpy as np
import pandas as pd
from dash import Input, Output, State, dcc, html, no_update
from dash.exceptions import PreventUpdate

from impakt.web.callbacks.plot_callbacks import _resolve_channels
from impakt.web.state import AppState


def register_export_callbacks(app: dash.Dash, app_state: AppState) -> None:
    """Register export-related callbacks."""

    @app.callback(
        Output("download-export", "data"),
        [
            Input("export-csv-btn", "n_clicks"),
        ],
        [
            State("selected-channels-store", "data"),
            State("cfc-select", "value"),
            State("y-align-check", "value"),
            State("x-align-method", "value"),
            State("x-align-value", "value"),
            State("show-resultant", "value"),
        ],
        prevent_initial_call=True,
    )
    def export_csv(
        n_clicks: int | None,
        selected_keys: list[str] | None,
        cfc_value: str,
        y_align: bool,
        x_align_method: str,
        x_align_value: float | None,
        show_resultant: bool,
    ) -> Any:
        if not n_clicks or not selected_keys:
            raise PreventUpdate

        channels = _resolve_channels(
            selected_keys,
            app_state,
            cfc_value,
            y_align,
            x_align_method or "none",
            x_align_value,
            show_resultant,
        )

        if not channels:
            raise PreventUpdate

        # Build DataFrame: first column is time from the first channel,
        # then one column per channel
        ref_time = channels[0][1].time

        data: dict[str, Any] = {"time_s": ref_time}
        for label, ch in channels:
            # Interpolate to common time base if needed
            if len(ch.time) == len(ref_time) and np.allclose(ch.time, ref_time):
                data[f"{label} [{ch.unit}]"] = ch.data
            else:
                data[f"{label} [{ch.unit}]"] = np.interp(ref_time, ch.time, ch.data)

        df = pd.DataFrame(data)

        # Generate filename
        primary = app_state.primary_test
        test_id = primary.test_id if primary else "export"
        cfc_suffix = f"_CFC{cfc_value}" if cfc_value != "none" else ""

        return dcc.send_data_frame(
            df.to_csv,
            f"{test_id}{cfc_suffix}_channels.csv",
            index=False,
        )

    @app.callback(
        Output("report-status", "children"),
        [Input("generate-report-btn", "n_clicks")],
        [State("protocol-select", "value")],
        prevent_initial_call=True,
    )
    def generate_report(n_clicks: int | None, protocol: str) -> Any:
        if not n_clicks:
            raise PreventUpdate

        primary = app_state.primary_test
        if primary is None:
            return html.Div("No test loaded.", className="text-danger small")

        from impakt.web.components.criteria import auto_compute_criteria, score_protocol

        criteria = auto_compute_criteria(primary.data)
        if not criteria:
            return html.Div("No criteria to report.", className="text-warning small")

        protocol_result = score_protocol(criteria, protocol)
        if protocol_result is None:
            return html.Div("Protocol scoring failed.", className="text-danger small")

        # Generate report
        try:
            from impakt.report.engine import generate_protocol_report
            import tempfile

            with tempfile.NamedTemporaryFile(suffix=".html", delete=False, mode="w") as f:
                from impakt.report.engine import _fallback_protocol_html

                html_content = _fallback_protocol_html(protocol_result, primary.data.metadata)
                f.write(html_content)
                report_path = f.name

            return html.Div(
                [
                    html.Span("Report generated: ", className="small text-success"),
                    html.Code(report_path, style={"fontSize": "10px"}),
                ]
            )
        except Exception as e:
            return html.Div(f"Report generation failed: {e}", className="text-danger small")
