# Copyright (C) 2025 Andreas Rettig
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

import wx  # type: ignore


def _detect_german() -> bool:
    # wx-Locale ist maßgeblich (wird von KiCAD bei Sprachwahl gesetzt).
    # Wenn sie verfügbar ist, wird sie direkt ausgewertet – kein Fallback.
    try:
        loc = wx.GetLocale()
        if loc is not None:
            return loc.GetName().lower().startswith("de")
    except Exception:
        pass
    # Fallback nur wenn wx keine Locale gesetzt hat
    try:
        import locale
        code = (locale.getlocale()[0] or locale.getdefaultlocale()[0] or "")
        return code.lower().startswith("de")
    except Exception:
        pass
    return False


_is_german = _detect_german()

# Übersetzungstabelle DE / EN
_T = {
    "title":        "Lochraster Generator",
    "grid":         "Rastergröße"        if _is_german else "Grid Size",
    "cols":         "Spalten:"           if _is_german else "Columns:",
    "rows":         "Zeilen:"            if _is_german else "Rows:",
    "type":         "Typ"                if _is_german else "Type",
    "vias":         "Einzelne Vias (keine Kupferstreifen)"
                                         if _is_german else "Individual vias (no copper strips)",
    "strips":       "Kupferstreifen"     if _is_german else "Copper strips",
    "dir_lbl":      "  Streifenrichtung:"if _is_german else "  Strip direction:",
    "dir_h":        "Horizontal (Zeilen)"if _is_german else "Horizontal (rows)",
    "dir_v":        "Vertikal (Spalten)" if _is_german else "Vertical (columns)",
    "sides":        "Lagen"              if _is_german else "Layers",
    "single":       "Einseitig  –  Streifen/Vias auf B.Cu"
                                         if _is_german else "Single-sided  –  strips/vias on B.Cu",
    "double_ortho": "Zweiseitig  –  orthogonal (B.Cu ⊥ F.Cu)"
                                         if _is_german else "Double-sided  –  orthogonal (B.Cu ⊥ F.Cu)",
    "double_same":  "Zweiseitig  –  gleiche Richtung (B.Cu ∥ F.Cu)"
                                         if _is_german else "Double-sided  –  same direction (B.Cu ∥ F.Cu)",
    "params":       "Parameter"          if _is_german else "Parameters",
    "drill":        "Bohrdurchmesser (mm):"
                                         if _is_german else "Drill diameter (mm):",
    "pad":          "Via-/Pad-Durchmesser (mm):"
                                         if _is_german else "Via/pad diameter (mm):",
    "track":        "Streifenbreite (mm):"
                                         if _is_german else "Strip width (mm):",
    "wire":         "Drahtbrücken"       if _is_german else "Wire Bridges",
    "wire_chk":     "Drahtbrücken-Lagen aktivieren (In1_Cu ↑ / In2_Cu ↓)"
                                         if _is_german else "Enable wire bridge layers (In1_Cu ↑ / In2_Cu ↓)",
    "wire_top":     "Drahtbruecken_oben" if _is_german else "Wire_Bridges_top",
    "wire_bot":     "Drahtbruecken_unten"if _is_german else "Wire_Bridges_bottom",
    "ok":           "Erzeugen"           if _is_german else "Generate",
    "cancel":       "Abbrechen"          if _is_german else "Cancel",
}


class LochrasterDialog(wx.Dialog):
    """Settings dialog for the Lochraster Generator."""

    def __init__(self, parent):
        super().__init__(
            parent,
            title=_T["title"],
            style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
        )
        self._build_ui()
        self.Fit()
        self.Centre()

    # ------------------------------------------------------------------
    # UI
    # ------------------------------------------------------------------

    def _build_ui(self):
        main = wx.BoxSizer(wx.VERTICAL)

        main.Add(self._build_grid_section(), 0, wx.EXPAND | wx.ALL, 8)
        main.Add(self._build_type_section(), 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 8)
        main.Add(self._build_sides_section(), 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 8)
        main.Add(self._build_wire_section(), 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 8)
        main.Add(self._build_param_section(), 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 8)
        main.Add(self._build_buttons(), 0, wx.EXPAND | wx.ALL, 8)

        self.SetSizer(main)
        self._update_controls()

        # Set defaults after all widgets are built (locale-safe)
        self.spin_drill.SetValue(1.0)
        self.spin_pad.SetValue(1.5)
        self.spin_track.SetValue(2.0)

    def _build_grid_section(self):
        box = wx.StaticBox(self, label=_T["grid"])
        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
        fg = wx.FlexGridSizer(2, 2, 4, 8)
        fg.AddGrowableCol(1)

        fg.Add(wx.StaticText(self, label=_T["cols"]), 0, wx.ALIGN_CENTER_VERTICAL)
        self.spin_cols = wx.SpinCtrl(self, value="30", min=2, max=300)
        fg.Add(self.spin_cols, 1, wx.EXPAND)

        fg.Add(wx.StaticText(self, label=_T["rows"]), 0, wx.ALIGN_CENTER_VERTICAL)
        self.spin_rows = wx.SpinCtrl(self, value="20", min=2, max=300)
        fg.Add(self.spin_rows, 1, wx.EXPAND)

        sizer.Add(fg, 0, wx.EXPAND | wx.ALL, 6)
        return sizer

    def _build_type_section(self):
        box = wx.StaticBox(self, label=_T["type"])
        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)

        self.radio_vias = wx.RadioButton(self, label=_T["vias"], style=wx.RB_GROUP)
        self.radio_strips = wx.RadioButton(self, label=_T["strips"])
        sizer.Add(self.radio_vias, 0, wx.ALL, 4)
        sizer.Add(self.radio_strips, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 4)

        dir_sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.lbl_dir = wx.StaticText(self, label=_T["dir_lbl"])
        dir_sizer.Add(self.lbl_dir, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 6)
        self.choice_dir = wx.Choice(self, choices=[_T["dir_h"], _T["dir_v"]])
        self.choice_dir.SetSelection(0)
        dir_sizer.Add(self.choice_dir)
        sizer.Add(dir_sizer, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 4)

        self.radio_vias.Bind(wx.EVT_RADIOBUTTON, self._on_type_changed)
        self.radio_strips.Bind(wx.EVT_RADIOBUTTON, self._on_type_changed)

        return sizer

    def _build_sides_section(self):
        box = wx.StaticBox(self, label=_T["sides"])
        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)

        self.radio_single = wx.RadioButton(self, label=_T["single"], style=wx.RB_GROUP)
        self.radio_double = wx.RadioButton(self, label=_T["double_ortho"])
        self.radio_double_same = wx.RadioButton(self, label=_T["double_same"])
        sizer.Add(self.radio_single, 0, wx.ALL, 4)
        sizer.Add(self.radio_double, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 4)
        sizer.Add(self.radio_double_same, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 4)

        self.radio_single.Bind(wx.EVT_RADIOBUTTON, self._on_sides_changed)
        self.radio_double.Bind(wx.EVT_RADIOBUTTON, self._on_sides_changed)
        self.radio_double_same.Bind(wx.EVT_RADIOBUTTON, self._on_sides_changed)

        return sizer

    def _build_wire_section(self):
        box = wx.StaticBox(self, label=_T["wire"])
        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
        self.chk_wire = wx.CheckBox(self, label=_T["wire_chk"])
        sizer.Add(self.chk_wire, 0, wx.ALL, 4)
        return sizer

    def _build_param_section(self):
        box = wx.StaticBox(self, label=_T["params"])
        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
        fg = wx.FlexGridSizer(3, 2, 4, 8)
        fg.AddGrowableCol(1)

        fg.Add(wx.StaticText(self, label=_T["drill"]), 0, wx.ALIGN_CENTER_VERTICAL)
        self.spin_drill = wx.SpinCtrlDouble(self, min=0.3, max=2.5, initial=1.0, inc=0.05)
        self.spin_drill.SetDigits(2)
        fg.Add(self.spin_drill, 1, wx.EXPAND)

        fg.Add(wx.StaticText(self, label=_T["pad"]), 0, wx.ALIGN_CENTER_VERTICAL)
        self.spin_pad = wx.SpinCtrlDouble(self, min=0.5, max=3.0, initial=1.5, inc=0.05)
        self.spin_pad.SetDigits(2)
        fg.Add(self.spin_pad, 1, wx.EXPAND)

        self.lbl_track = wx.StaticText(self, label=_T["track"])
        fg.Add(self.lbl_track, 0, wx.ALIGN_CENTER_VERTICAL)
        self.spin_track = wx.SpinCtrlDouble(self, min=0.1, max=2.54, initial=2.0, inc=0.05)
        self.spin_track.SetDigits(2)
        fg.Add(self.spin_track, 1, wx.EXPAND)

        sizer.Add(fg, 0, wx.EXPAND | wx.ALL, 6)
        return sizer

    def _build_buttons(self):
        sizer = wx.StdDialogButtonSizer()
        ok = wx.Button(self, wx.ID_OK, _T["ok"])
        ok.SetDefault()
        cancel = wx.Button(self, wx.ID_CANCEL, _T["cancel"])
        sizer.AddButton(ok)
        sizer.AddButton(cancel)
        sizer.Realize()
        return sizer

    # ------------------------------------------------------------------
    # Event handlers
    # ------------------------------------------------------------------

    def _on_type_changed(self, _event):
        self._update_controls()

    def _on_sides_changed(self, _event):
        self._update_controls()

    def _update_controls(self):
        strips = self.radio_strips.GetValue()
        self.lbl_dir.Enable(strips)
        self.choice_dir.Enable(strips)
        self.lbl_track.Enable(strips)
        self.spin_track.Enable(strips)
        self.radio_double_same.Enable(strips)
        if not strips and self.radio_double_same.GetValue():
            self.radio_double.SetValue(True)

    # ------------------------------------------------------------------
    # Result
    # ------------------------------------------------------------------

    def get_settings(self):
        if self.radio_single.GetValue():
            sides = "single"
        elif self.radio_double.GetValue():
            sides = "double_ortho"
        else:
            sides = "double_same"

        return {
            "cols": self.spin_cols.GetValue(),
            "rows": self.spin_rows.GetValue(),
            "type": "strips" if self.radio_strips.GetValue() else "vias",
            "direction": "horizontal" if self.choice_dir.GetSelection() == 0 else "vertical",
            "sides": sides,
            "drill_mm": self.spin_drill.GetValue(),
            "pad_mm": self.spin_pad.GetValue(),
            "track_mm": self.spin_track.GetValue(),
            "wire_bridges": self.chk_wire.GetValue(),
            "wire_name_top": _T["wire_top"],
            "wire_name_bot": _T["wire_bot"],
        }
