using System;
using Gtk;
using System.Collections.Generic;
using UI = Gtk.Builder.ObjectAttribute;

public class SettingsWindow
{
    [UI] private Label      ComPortLabel     = null;
    [UI] private ComboBoxText ComPortComboBox = null;
    [UI] private Button     ConnectButton    = null;
    [UI] private Button     AutoConnectButton = null;
    [UI] private Button     RefreshButton    = null;
    [UI] private Button     SettingBackButton       = null;
    [UI] private Label      StatusLabel      = null;
    [UI] private Label      LogLabel         = null;
    [UI] private TextView   LogtextBox       = null;

    // private readonly Dictionary<string, Button> _buttonsById;
    // private readonly Dictionary<string, Label> _labelsById;
    // internal Language _Language;
    private readonly Language _lang;
    private bool _connected;

    private const int MaxLogLines = 500;

    private readonly ArduinoConnection _arduino;
    private string[] _ports = new string[0];

    /// <summary>Raised after the window hides itself, so the caller can re-show the main window.</summary>
    public event EventHandler BackRequested;


     public SettingsWindow(Builder builder, ArduinoConnection arduino, Language language)
    {
        builder.Autoconnect(this);
        _arduino = arduino;
        _lang = language;

        // Title = "Settings";
        // ComPortLabel.Text = "COM Port";
        // LogLabel.Text = "Log";
        LogtextBox.Editable = false;
        LogtextBox.WrapMode = WrapMode.WordChar;

        RefreshButton.Clicked     += (s, e) => RefreshPorts();
        ConnectButton.Clicked     += OnConnectClicked;
        AutoConnectButton.Clicked += OnAutoConnectClicked;
        SettingBackButton.Clicked        += OnBackClicked;

        // DeleteEvent += (o, a) => { a.RetVal = true; OnBackClicked(o, EventArgs.Empty); };

        _arduino.Log               += AppendLog;
        _arduino.LineReceived      += OnLineReceived;
        _arduino.ConnectionChanged += OnConnectionChanged;

        _lang.Register("ComPortLabel",      ComPortLabel);
        _lang.Register("LogLabel",          LogLabel);
        _lang.Register("AutoConnectButton", AutoConnectButton);
        _lang.Register("RefreshButton",     RefreshButton);
        _lang.Register("SettingBackButton",        SettingBackButton);
        _lang.RegisterDynamic("ConnectButton", ConnectButton);   // set in OnConnectionChanged
        _lang.RegisterDynamic("StatusLabel",   StatusLabel);
        _lang.Changed += (s, e) => OnConnectionChanged(_connected);

        //  _buttonsById = new Dictionary<string, Button>
        //  {
        //     { "ConnectButton", ConnectButton },
        //     { "AutoConnectButton", AutoConnectButton },
        //     { "RefreshButton", RefreshButton },
        //     { "BackButton",   BackButton   },
        //  };

        // // CSS ID selectors (#Option1Button etc.) need the widget Name set explicitly
        // foreach (var kvp in _buttonsById)
        //     kvp.Value.Name = kvp.Key;
        
        // _Language = new Language(_buttonsById);
        // // _Language.ApplyLanguages(Language.LanguageSwitchValue); 

        RefreshPorts();
        OnConnectionChanged(_arduino.IsOpen);
    }

    // ---------- UI actions ----------

    private void RefreshPorts()
    {
        ComPortComboBox.RemoveAll();
        _ports = ArduinoConnection.ListPorts();

        foreach (string p in _ports)
            ComPortComboBox.AppendText(p);

        if (_ports.Length > 0)
        {
            ComPortComboBox.Active = 0;
            AppendLog(_lang.Format("Log.PortsFound", _ports.Length));
        }
        else
        {
            AppendLog(_lang["Log.NoPorts"]);
        }
    }

    private void OnConnectClicked(object sender, EventArgs e)
    {
        if (_arduino.IsOpen)
        {
            _arduino.Disconnect();
            return;
        }

        string port = ComPortComboBox.ActiveText;
        if (string.IsNullOrEmpty(port))
        {
            AppendLog(_lang["Log.SelectPort"]);
            return;
        }
        _arduino.Connect(port);
    }

    private async void OnAutoConnectClicked(object sender, EventArgs e)
    {
        AutoConnectButton.Sensitive = false;
        ConnectButton.Sensitive = false;
        AppendLog(_lang["Log.Scanning"]);

        string found = await _arduino.DetectPortAsync();

        if (found != null)
        {
            RefreshPorts();
            SelectPort(found);
            _arduino.Connect(found);
        }
        else
        {
            AppendLog(_lang["Log.DeviceNotFound"]);
        }

        AutoConnectButton.Sensitive = true;
        ConnectButton.Sensitive = true;
    }

    private void OnBackClicked(object sender, EventArgs e)
    {
        // Hide();
        BackRequested?.Invoke(this, EventArgs.Empty);
    }

    private void SelectPort(string portName)
    {
        for (int i = 0; i < _ports.Length; i++)
        {
            if (_ports[i] == portName)
            {
                ComPortComboBox.Active = i;
                return;
            }
        }
    }

    // ---------- device events ----------

    private void OnConnectionChanged(bool connected)
    {
        _connected = connected;

        ConnectButton.Label = connected
            ? _lang["ConnectButton.Disconnect"]
            : _lang["ConnectButton.Connect"];

        StatusLabel.Text = connected
            ? _lang.Format("StatusLabel.Connected", _arduino.PortName)
            : _lang["StatusLabel.Disconnected"];

        ComPortComboBox.Sensitive = !connected;
        RefreshButton.Sensitive   = !connected;

        StyleContext ctx = StatusLabel.StyleContext;
        ctx.RemoveClass(connected ? "status-off" : "status-on");
        ctx.AddClass(connected ? "status-on" : "status-off");
    }

    private void OnLineReceived(string line)
    {
        // Same filtering Form2.cs applied before parsing.
        if (line.StartsWith("Send Status:")) return;
        if (line.StartsWith("\u2713") || line.StartsWith("\u2717")) return;

        if (line.Contains("ESPNOW_CONNECTED"))    { AppendLog(_lang["Log.EspNowConnected"]);    return; }
        if (line.Contains("ESPNOW_DISCONNECTED")) { AppendLog(_lang["Log.EspNowDisconnected"]); return; }

        AppendLog(line);
    }

    // ---------- log ----------

    public void AppendLog(string message)
    {
        TextBuffer buf = LogtextBox.Buffer;

        TextIter end = buf.EndIter;
        buf.Insert(ref end, $"[{DateTime.Now:HH:mm:ss.fff}] {message}\n");

        if (buf.LineCount > MaxLogLines)
        {
            TextIter start = buf.StartIter;
            TextIter cut = buf.GetIterAtLine(buf.LineCount - MaxLogLines);
            buf.Delete(ref start, ref cut);
        }

        TextMark mark = buf.CreateMark(null, buf.EndIter, false);
        LogtextBox.ScrollToMark(mark, 0, false, 0, 0);
        buf.DeleteMark(mark);
    }
}