"""Builder for radar settings section."""

from __future__ import annotations

import json

from PyQt6.QtWidgets import (
    QCheckBox,
    QComboBox,
    QGroupBox,
    QLabel,
    QLineEdit,
    QPlainTextEdit,
    QVBoxLayout,
    QWidget,
)

from python_app.gui.controllers.sections.layout_helpers import build_two_column_form_widget


def build_radar_group(owner) -> QGroupBox:
    """Create radar settings controls and labels."""
    group = QGroupBox("Radar")
    layout = QVBoxLayout(group)
    layout.setContentsMargins(10, 10, 10, 10)
    layout.setSpacing(8)
    defaults = owner._defaults_config.radar

    owner._vna_radar_settings_panel = QWidget(group)
    vna_layout = QVBoxLayout(owner._vna_radar_settings_panel)
    vna_layout.setContentsMargins(0, 0, 0, 0)
    vna_layout.setSpacing(8)

    owner._start_hz_input = QLineEdit(f"{defaults.sweep.start_hz:g}")
    owner._stop_hz_input = QLineEdit(f"{defaults.sweep.stop_hz:g}")
    owner._points_input = QLineEdit(str(defaults.sweep.points))
    owner._ifbw_input = QLineEdit(f"{defaults.sweep.if_bandwidth_hz:g}")
    owner._power_input = QLineEdit(f"{defaults.sweep.power_dbm:g}")
    owner._power_input.setToolTip("Stimulus power configured in the active profile.")
    owner._start_hz_input.editingFinished.connect(owner._on_radar_sweep_limits_changed)
    owner._stop_hz_input.editingFinished.connect(owner._on_radar_sweep_limits_changed)
    owner._points_input.editingFinished.connect(owner._on_radar_sweep_limits_changed)
    owner._ifbw_input.editingFinished.connect(owner._on_radar_sweep_limits_changed)
    owner._power_input.editingFinished.connect(owner._on_radar_sweep_limits_changed)

    owner._radar_start_label = QLabel("Start Hz")
    owner._radar_stop_label = QLabel("Stop Hz")
    owner._radar_points_label = QLabel("Points")
    owner._radar_ifbw_label = QLabel("IF BW Hz")
    owner._radar_power_label = QLabel("Stimulus Power dBm")

    owner._radar_limits_hint = QLabel("Device limits are not available.")
    owner._radar_limits_hint.setObjectName("hintLabel")

    vna_layout.addWidget(
        build_two_column_form_widget(
            group,
            [
                (owner._radar_start_label, owner._start_hz_input),
                (owner._radar_stop_label, owner._stop_hz_input),
                (owner._radar_points_label, owner._points_input),
                (owner._radar_ifbw_label, owner._ifbw_input),
                (owner._radar_power_label, owner._power_input),
            ],
        )
    )
    vna_layout.addWidget(owner._radar_limits_hint)

    owner._adc_radar_settings_panel = _build_adc_settings_panel(owner, group)

    layout.addWidget(owner._vna_radar_settings_panel)
    layout.addWidget(owner._adc_radar_settings_panel)
    owner._set_radar_settings_mode(owner._defaults_config.is_kamil_adc)
    return group


def _build_adc_settings_panel(owner, parent: QWidget) -> QWidget:
    """Create controls for the external ADC collector and optical board."""
    panel = QWidget(parent)
    layout = QVBoxLayout(panel)
    layout.setContentsMargins(0, 0, 0, 0)
    layout.setSpacing(8)

    adc = owner._defaults_config.radar.kamil_adc
    optical = owner._defaults_config.radar.laser_control
    manual = optical.manual
    variation = optical.variation

    owner._adc_project_dir_input = QLineEdit(adc.project_dir)
    owner._adc_executable_path_input = QLineEdit(adc.executable_path)
    owner._adc_tty_path_input = QLineEdit(adc.tty_path)
    owner._adc_args_input = _plain_text("\n".join(adc.args))
    owner._adc_env_input = _plain_text(json.dumps(adc.env, indent=2, sort_keys=True) if adc.env else "{}")
    owner._adc_startup_timeout_s_input = QLineEdit(f"{adc.startup_timeout_s:g}")
    owner._adc_sweep_timeout_s_input = QLineEdit(f"{adc.sweep_timeout_s:g}")
    owner._adc_stop_timeout_s_input = QLineEdit(f"{adc.stop_timeout_s:g}")

    owner._optical_enabled_checkbox = QCheckBox()
    owner._optical_enabled_checkbox.setChecked(bool(optical.enabled))
    owner._optical_port_input = QLineEdit(optical.port)
    owner._optical_mode_combo = QComboBox()
    owner._optical_mode_combo.addItems(["manual", "variation"])
    owner._set_combo_current_text(owner._optical_mode_combo, optical.mode)
    owner._optical_pi_coeff1_p_input = QLineEdit(str(optical.pi_coeff1_p))
    owner._optical_pi_coeff1_i_input = QLineEdit(str(optical.pi_coeff1_i))
    owner._optical_pi_coeff2_p_input = QLineEdit(str(optical.pi_coeff2_p))
    owner._optical_pi_coeff2_i_input = QLineEdit(str(optical.pi_coeff2_i))

    owner._optical_manual_temp1_input = QLineEdit(f"{manual.temp1:g}")
    owner._optical_manual_temp2_input = QLineEdit(f"{manual.temp2:g}")
    owner._optical_manual_current1_input = QLineEdit(f"{manual.current1:g}")
    owner._optical_manual_current2_input = QLineEdit(f"{manual.current2:g}")

    owner._optical_variation_type_combo = QComboBox()
    owner._optical_variation_type_combo.addItems(
        [
            "CHANGE_CURRENT_LD1",
            "CHANGE_CURRENT_LD2",
            "CHANGE_TEMPERATURE_LD1",
            "CHANGE_TEMPERATURE_LD2",
        ]
    )
    owner._set_combo_current_text(owner._optical_variation_type_combo, variation.variation_type)
    owner._optical_static_temp1_input = QLineEdit(f"{variation.static_temp1:g}")
    owner._optical_static_temp2_input = QLineEdit(f"{variation.static_temp2:g}")
    owner._optical_static_current1_input = QLineEdit(f"{variation.static_current1:g}")
    owner._optical_static_current2_input = QLineEdit(f"{variation.static_current2:g}")
    owner._optical_min_value_input = QLineEdit(f"{variation.min_value:g}")
    owner._optical_max_value_input = QLineEdit(f"{variation.max_value:g}")
    owner._optical_step_input = QLineEdit(f"{variation.step:g}")
    owner._optical_time_step_input = QLineEdit(str(variation.time_step))
    owner._optical_delay_time_input = QLineEdit(str(variation.delay_time))

    layout.addWidget(
        build_two_column_form_widget(
            panel,
            [
                ("Project dir", owner._adc_project_dir_input),
                ("Executable path", owner._adc_executable_path_input),
                ("TTY path", owner._adc_tty_path_input),
                ("Arguments", owner._adc_args_input),
                ("Environment JSON", owner._adc_env_input),
                ("Startup timeout s", owner._adc_startup_timeout_s_input),
                ("Read timeout s", owner._adc_sweep_timeout_s_input),
                ("Stop timeout s", owner._adc_stop_timeout_s_input),
                ("Board enabled", owner._optical_enabled_checkbox),
                ("Board port", owner._optical_port_input),
                ("Board mode", owner._optical_mode_combo),
                ("PI 1 P", owner._optical_pi_coeff1_p_input),
                ("PI 1 I", owner._optical_pi_coeff1_i_input),
                ("PI 2 P", owner._optical_pi_coeff2_p_input),
                ("PI 2 I", owner._optical_pi_coeff2_i_input),
            ],
            split_index=8,
        )
    )

    owner._optical_manual_panel = build_two_column_form_widget(
        panel,
        [
            ("Temperature 1", owner._optical_manual_temp1_input),
            ("Temperature 2", owner._optical_manual_temp2_input),
            ("Current 1", owner._optical_manual_current1_input),
            ("Current 2", owner._optical_manual_current2_input),
        ],
    )
    owner._optical_variation_panel = build_two_column_form_widget(
        panel,
        [
            ("Variation type", owner._optical_variation_type_combo),
            ("Static temp 1", owner._optical_static_temp1_input),
            ("Static temp 2", owner._optical_static_temp2_input),
            ("Static current 1", owner._optical_static_current1_input),
            ("Static current 2", owner._optical_static_current2_input),
            ("Min value", owner._optical_min_value_input),
            ("Max value", owner._optical_max_value_input),
            ("Step", owner._optical_step_input),
            ("Time step", owner._optical_time_step_input),
            ("Delay time", owner._optical_delay_time_input),
        ],
        split_index=5,
    )
    layout.addWidget(owner._optical_manual_panel)
    layout.addWidget(owner._optical_variation_panel)

    _connect_adc_settings(owner)
    owner._sync_adc_settings_controls()
    return panel


def _plain_text(text: str) -> QPlainTextEdit:
    widget = QPlainTextEdit(text)
    widget.setMaximumHeight(76)
    return widget


def _connect_adc_settings(owner) -> None:
    text_widgets = [
        owner._adc_project_dir_input,
        owner._adc_executable_path_input,
        owner._adc_tty_path_input,
        owner._adc_startup_timeout_s_input,
        owner._adc_sweep_timeout_s_input,
        owner._adc_stop_timeout_s_input,
        owner._optical_port_input,
        owner._optical_pi_coeff1_p_input,
        owner._optical_pi_coeff1_i_input,
        owner._optical_pi_coeff2_p_input,
        owner._optical_pi_coeff2_i_input,
        owner._optical_manual_temp1_input,
        owner._optical_manual_temp2_input,
        owner._optical_manual_current1_input,
        owner._optical_manual_current2_input,
        owner._optical_static_temp1_input,
        owner._optical_static_temp2_input,
        owner._optical_static_current1_input,
        owner._optical_static_current2_input,
        owner._optical_min_value_input,
        owner._optical_max_value_input,
        owner._optical_step_input,
        owner._optical_time_step_input,
        owner._optical_delay_time_input,
    ]
    for widget in text_widgets:
        widget.editingFinished.connect(owner._reset_preprocess_selection_after_radar_key_change)
    owner._adc_args_input.textChanged.connect(owner._reset_preprocess_selection_after_radar_key_change)
    owner._adc_env_input.textChanged.connect(owner._reset_preprocess_selection_after_radar_key_change)
    owner._optical_variation_type_combo.currentTextChanged.connect(
        owner._reset_preprocess_selection_after_radar_key_change
    )

    def sync_and_reset() -> None:
        owner._sync_adc_settings_controls()
        owner._reset_preprocess_selection_after_radar_key_change()

    owner._optical_enabled_checkbox.toggled.connect(sync_and_reset)
    owner._optical_mode_combo.currentTextChanged.connect(sync_and_reset)
