using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.LogicalTree;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.Threading;
using AvaloniaApplication1.DataBase;
using DaireApplication.DataBase;
using DaireApplication.ViewModels;
using DaireApplication.Views;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Numerics;
using System.Reflection.Emit;
using System.Reflection.PortableExecutable;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

namespace DaireApplication;

public partial class Software : UserControl
{
    private MainWindow? _mainWindow;
    public UserTable _user = new();
    public ScreeenTable _screeen = new();
    private Process? _keyboardProcess;
    private bool _isWindowLoaded = false;
    TextBox targetText = new TextBox();
    int oldValue = 0;
    bool _isAdvSetting;
    bool _isFromManualControl;

    public event PropertyChangedEventHandler? PropertyChanged;

    private void RaisePropertyChanged([CallerMemberName] string? name = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));

    public ObservableCollection<string> SerialPorts { get; } = new() { "Choose COM" };

    private string? _selectedPort;
    public string? SelectedPort 
    {
        get => _selectedPort;
        set
        {
            if (_selectedPort != value)
            {
                _selectedPort = value;
                RaisePropertyChanged();
            }
        }
    }
    public Software(MainWindow mainWindow,bool isAdvSetting=false, bool isFromManualControl=false)
    {
        _mainWindow = mainWindow;
        _isAdvSetting = isAdvSetting;
        _isFromManualControl = isFromManualControl;
        foreach (var port in SerialPort.GetPortNames())
        {
            SerialPorts.Add(port);
        }
        var screen = _screeen.ReadScreens()[0];

        InitializeComponent();
        this.Loaded += OnWindowLoaded;
        if (SerialPorts.Count - 1 > 0)
        {
            if (!string.IsNullOrEmpty(screen.port))
            {
                SerialPorts[0] = "Close Comunication";
                SelectedPort = screen.port;

            }
            else
            {
                SerialPorts[0] = "Choose COM";

                SelectedPort = SerialPorts[0];

            }
        }     
        else
            SelectedPort = SerialPorts[0];
        DataContext = this;

        setDefaultSettings();
        showDefaultValues();
        sendingTimetxt.AddHandler(TextInputEvent, OnTextInput, RoutingStrategies.Tunnel);
        warningLimit.AddHandler(TextInputEvent, OnTextInput, RoutingStrategies.Tunnel);
        errorLimit.AddHandler(TextInputEvent, OnTextInput, RoutingStrategies.Tunnel);
        passwordBorder.AddHandler(InputElement.PointerPressedEvent, OnTextBoxFocused, RoutingStrategies.Tunnel, handledEventsToo: true);
        warningBorder.AddHandler(InputElement.PointerPressedEvent, OnTextBoxFocused, RoutingStrategies.Tunnel, handledEventsToo: true);
        errorBorder.AddHandler(InputElement.PointerPressedEvent, OnTextBoxFocused, RoutingStrategies.Tunnel, handledEventsToo: true);
        AttachHandlers(_mainWindow.logoBtn, AdvanceSettingsView);
        AttachHandlers(_mainWindow.UserName, CloseApplication);

    }
    public void AttachHandlers(Button button, System.EventHandler<Avalonia.Input.HoldingRoutedEventArgs> func)
    {
        if (button != null)
        {
            button.Holding += func;

            button.PointerPressed += (sender, e) =>
            {
                // Simulate a long press on any pointer (mouse or touch)
                var point = e.GetPosition(button);
                func(sender, new HoldingRoutedEventArgs(HoldingState.Started, point, e.Pointer.Type));
            };

            button.PointerReleased += (sender, e) =>
            {
                // End simulated long press
                var point = e.GetPosition(button);
                func(sender, new HoldingRoutedEventArgs(HoldingState.Completed, point, e.Pointer.Type));
            };
        }
    }
    public Software()
    {
        InitializeComponent();

    }
    public void AdvanceSettingsView(object? sender, RoutedEventArgs e)
    {
        if (_mainWindow.ContentArea.Content == this)
        {
            _mainWindow.ContentArea.Content = new AdvanceSettings(_mainWindow,false,true);

        }

    }
    public static void CloseApplication(object? sender, RoutedEventArgs e)
    {
        var lifetime = Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime;
        lifetime?.Shutdown(); // This should correctly shut down the application
    }
    private void OnWindowLoaded(object? sender, RoutedEventArgs e)
    {
        _isWindowLoaded = true;
    }
    private void OnTextInput(object? sender, TextInputEventArgs e)
    {
        if (sender is TextBox textBox)
        {
            string newText = textBox.Text + e.Text;
            if (!Regex.IsMatch(newText, @"^\d*\.?\d*$"))
            {
                e.Handled = true;
            }
        }
    }

    private void hidePasswordPopUp(object sender, RoutedEventArgs e)
    {

        passwordInput.Text = "";
        CloseKeyboard();
        passwordPopupOverlay.IsVisible = false;
    }
    private async void passwordSaveClick(object? sender, RoutedEventArgs e)
    {
        var user = _user.ReadUsers().FirstOrDefault(x=>x.UserName.ToLower()==titelMsg.Tag.ToString().ToLower());
        user.Password = passwordInput.Text;
        user.IsActive = isActivePass.IsChecked.Value;
        if (_user.UpdateUser(user))
        {
            //await MainWindow.MessageBox.Show(_mainWindow, "Password Changed Sucseccfully", "Sucsecc");
            passwordInput.Text = "";
            CloseKeyboard();

            passwordPopupOverlay.IsVisible = false;
        }
        else
        {
            if (_keyboardProcess != null)
            {
                _keyboardProcess.Kill();
            }
            await MainWindow.MessageBox.Show(_mainWindow, "Password Does Not Changed Try Again", "Error");
            _mainWindow.Topmost = false;
        }

    }
    private void showChangePasswordPopUp(object? sender, RoutedEventArgs e)
    {
        if (sender is Button button)
        {
            var text = button.Content as TextBlock;
            titelMsg.Text = $"New {text.Text} Password:";
            titelMsg.Tag =  text.Text;
            var user = _user.ReadUsers().FirstOrDefault(x => x.UserName.ToLower() == titelMsg.Tag.ToString().ToLower());
            isActivePass.IsVisible = true;
            isActivePass.IsChecked = user.IsActive;
            passwordPopupOverlay.IsVisible = true;
        }


    }

    private void hideScreenPopUp(object sender, RoutedEventArgs e)
    {
        slider.Value = 0;
        secreenPopupOverlay.IsVisible = false;
    }
    private async void screenSaveClick(object? sender, RoutedEventArgs e)
    {
        var screenData = _screeen.ReadScreens()?[0];
        string brightnessPath = "/sys/class/backlight/backlight/brightness"; // Try backlight1 if this fails

        if (titelSecreenMsg.Tag.ToString()== "BRIGHTNESS")
        {
            try
            {
                if (!string.IsNullOrEmpty(sliderValue.Text))
                {
                    int brightnessValue = (int)(Int32.Parse(sliderValue.Text) / 100.0 * 255);
                    screenData.brightness = Int32.Parse(sliderValue.Text);
                    _screeen.UpdateScreen(screenData);
                    File.WriteAllText(brightnessPath, brightnessValue.ToString());
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error: " + ex.Message);
            }
        }
       else if (titelSecreenMsg.Tag.ToString() == "AUTO DIM")
        {
            if (!string.IsNullOrEmpty(sliderValue.Text))
            {
                if ((screenData?.offSec / 60.0) < float.Parse(sliderValue.Text))
                {
                    if (_keyboardProcess != null)
                    {
                        _keyboardProcess.Kill();
                    }
                    await MainWindow.MessageBox.Show(_mainWindow, "AutoOff Value must be greater than AutoDim Value", "Error");
                    _mainWindow.Topmost = false;
                    return;
                }
                screenData.dimSec = float.Parse(sliderValue.Text) * 60;

                _screeen.UpdateScreen(screenData);
            }
           

        }
      else  if (titelSecreenMsg.Tag.ToString() == "AUTO OFF")
        {
            if (!string.IsNullOrEmpty(sliderValue.Text))
            {
                if ((screenData?.dimSec / 60.0)> float.Parse(sliderValue.Text))
                {
                    if (_keyboardProcess != null)
                    {
                        _keyboardProcess.Kill();
                    }
                    await MainWindow.MessageBox.Show(_mainWindow, "AutoOff Value must be greater than AutoDim Value", "Error");
                    _mainWindow.Topmost = false;

                    return;
                }
                 screenData.offSec = float.Parse(sliderValue.Text) * 60;

                _screeen.UpdateScreen(screenData);
            }
            

        }
        showDefaultValues();
        secreenPopupOverlay.IsVisible = false;


    }
    private void InnerPopupPointerPressed(object? sender, PointerPressedEventArgs e)
    {
        e.Handled = true;
    }
    private void showScreenPopUp(object? sender, RoutedEventArgs e)
    {
        if (sender is Button button)
        {
            var screenData = _screeen.ReadScreens()?[0];

            if (button.Tag.ToString() == "BRIGHTNESS")
            {
                slider.Maximum = 100;
                titelSecreenMsg.Text = $"Enter {button.Tag} percentage:";
                titelSecreenMsg.Tag = button.Tag;
                slider.Value = screenData.brightness;
                secreenPopupOverlay.IsVisible = true;
            }
            if (button.Tag.ToString() == "AUTO DIM")
            {
                slider.Maximum = 120;

                titelSecreenMsg.Text = $"Enter {button.Tag} value in min:";
                titelSecreenMsg.Tag = button.Tag;
                slider.Value = screenData.dimSec / 60;

                secreenPopupOverlay.IsVisible = true;
            }
            if (button.Tag.ToString() == "AUTO OFF")
            {
               slider.Maximum = 120;

                titelSecreenMsg.Text = $"Enter {button.Tag} value in min:";
                titelSecreenMsg.Tag = button.Tag;
                slider.Value = screenData.offSec / 60;

                secreenPopupOverlay.IsVisible = true;
            }

        }
        


    }
    private void OnSliderValueChanged(object? sender, RoutedEventArgs e)
    {
        if (sender is Slider slider)
        {
            var parent = slider.Parent as StackPanel;
            var targetText = parent.Children[1] as TextBlock;
           
            targetText.Text= slider.Value.ToString();
            //sliderValue.Text= slider.Value.ToString();

        }
        


    }
    private void changeValueClick(object? sender, RoutedEventArgs e)
    {
        if (sender is Button button)
        {
            var parent = button.Parent as StackPanel;
            var slider = parent.Children[1] as Slider;
            var grandParent = parent.Parent as StackPanel;
            var stack = grandParent.Children[0] as StackPanel;
            var targetText = stack.Children[1] as TextBlock;
            targetText.Text = slider.Value.ToString();
            if (button.Content=="+") // +
            {
                slider.Value = Int32.Parse(targetText.Text) + 1;

            }
            else // - 
            {
                if (Int32.Parse(targetText.Text)>0)
                {
                    slider.Value = Int32.Parse(targetText.Text) - 1;
                }

            }


        }

    }
    private void OnComSliderValueChanged(object? sender, RoutedEventArgs e)
    {
        if (sender is Slider slider)
        {
            var parent = slider.Parent.Parent as StackPanel;
            var stack = parent.Children[0] as StackPanel;
            var targetText = stack.Children[1] as TextBlock;
            targetText.Text= slider.Value.ToString();

        }
        


    }
    private void hideComPopUp(object sender, RoutedEventArgs e)
    {
        //comSlider.Value = 0;
        comPopupOverlay.IsVisible = false;
    }  
    private void hideTempPopUp(object sender, RoutedEventArgs e)
    {
        tempPopupOverlay.IsVisible = false;
    }
    private async void comSaveClick(object? sender, RoutedEventArgs e)
    {
        var screen = _screeen.ReadScreens()[0];
        var boundRateItem = boundRateComboBox.SelectedItem as ComboBoxItem;
        screen.boundRate = Int32.Parse(boundRateItem.Content.ToString());
        var stopbitsItem = stopBitsComboBox.SelectedItem as ComboBoxItem;
        screen.stopBits = Int32.Parse(stopbitsItem.Tag.ToString());
        var parityItem = parityComboBox.SelectedItem as ComboBoxItem;
        screen.parity = Int32.Parse(parityItem.Tag.ToString());
        screen.sendingTime = Int32.Parse(sendingTimetxt.Text);
       
        if (_screeen.UpdateScreen(screen))
        {
            _mainWindow.resetPort = true;
            _mainWindow.footerMsg.Text = "Connecting.....";
            _mainWindow.footerMsg.IsVisible = true;
            comPopupOverlay.IsVisible = false;

        }

    }
    private void showComPopUp(object? sender, RoutedEventArgs e)
    {
        var screen = _screeen.ReadScreens()[0];

        boundRateComboBox.SelectedIndex=int.Parse(boundRateComboBox.Items.OfType<ComboBoxItem>().FirstOrDefault(item => item.Content?.ToString() == screen.boundRate.ToString()).Tag.ToString());
        stopBitsComboBox.SelectedIndex = screen.stopBits;
        parityComboBox.SelectedIndex = screen.parity;
        sendingTimetxt.Text=screen.sendingTime.ToString();
        comPopupOverlay.IsVisible = true;
    } 
    private void ShowTempPopUp(object? sender, RoutedEventArgs e)
    {
        var screen = _screeen.ReadScreens()[0];
        warningLimit.Text=screen.warningLimit.ToString();
        errorLimit.Text=screen.errorLimit.ToString();
        tempPopupOverlay.IsVisible = true;
    }
    private void tempSaveBtn(object? sender, RoutedEventArgs e)
    {
        var screen = _screeen.ReadScreens()[0];
        screen.warningLimit = double.Parse(warningLimit.Text);
        screen.errorLimit = double.Parse(errorLimit.Text);
        _screeen.UpdateScreen(screen);
        CloseKeyboard();
        //if (_keyboardProcess != null)
        //{
        //    _keyboardProcess.Kill();

        //}

        tempPopupOverlay.IsVisible=false;
    }
    private void portChanged(object? sender, RoutedEventArgs e)
    {
        if (!_isWindowLoaded)
            return;
        if (sender is ComboBox comboBox)
        {
            if (comboBox.SelectedItem is string selectedItem)
            {
                var screen = _screeen.ReadScreens()[0];
                if (selectedItem.ToString()!= "Choose COM" && selectedItem.ToString()!= "Close Comunication")
                {
                    screen.port = selectedItem.ToString();
                    _screeen.UpdateScreen(screen);

                }
                else
                {
                    screen.port = "";
                    _screeen.UpdateScreen(screen);
                }
                boundRateComboBox.SelectedIndex = int.Parse(boundRateComboBox.Items.OfType<ComboBoxItem>().FirstOrDefault(item => item.Content?.ToString() == screen.boundRate.ToString()).Tag.ToString());
                stopBitsComboBox.SelectedIndex = screen.stopBits;
                parityComboBox.SelectedIndex = screen.parity;
                sendingTimetxt.Text = screen.sendingTime.ToString();
                this.comSaveButton.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));


            }

        }
    }


    private (string? fileName, string args) GetKeyboardCommand()
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            return ("osk.exe", "");
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            return ("onboard", ""); // or "florence", "matchbox-keyboard"
        return (null, "");
    }
  
    private async void OnTextBoxFocused(object? sender, PointerPressedEventArgs e)
    {
        if (_keyboardProcess is { HasExited: false })
            return;

        var (fileName, args) = GetKeyboardCommand();
        if (fileName is null)
            return;

        _keyboardProcess = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = fileName,
                Arguments = args,
                UseShellExecute = true,
                WorkingDirectory = "/usr/bin"
            },
            EnableRaisingEvents = true
        };


        try
        {
            _keyboardProcess.Start();



            Dispatcher.UIThread.Post(() =>
            {
                if (sender is Border border)
                {
                    var textbox = border.Child as TextBox;
                    textbox.SelectionStart = 0;
                    textbox.SelectionEnd = textbox.Text?.Length ?? 0;
                }
            });

        }
        catch
        {
            // fail silently if keyboard not found
        }
    }


    private void OnPopupOverlayPointerPressed(object sender, PointerPressedEventArgs e)
    {
        targetText.Text = oldValue.ToString();
        CancelComButton.Focus();

        keyBoardPopup.IsVisible = false;
    }
    private void OnKeyClick(object? sender, RoutedEventArgs e)
    {
        if (sender is Button button)
        {
            targetText.Text += button.Content;
        }
    }
    private void ShowNumberKeyBoard(object? sender, RoutedEventArgs e)
    {
        targetText = sendingTimetxt;
        oldValue = Int32.Parse(targetText.Text);
        targetText.Text = "";
        keyBoardPopup.IsVisible = true;
    } 
    private void OnBackClick(object? sender, RoutedEventArgs e)
    {
        if (!string.IsNullOrEmpty(targetText.Text))
        {
            // Remove the last character from the text box
            targetText.Text = targetText.Text.Remove(targetText.Text.Length - 1, 1);
        }

    }

    private void EnterClick(object? sender, RoutedEventArgs e)
    {

        CancelComButton.Focus();
        keyBoardPopup.IsVisible = false;
    }

    private void CloseKeyboard()
    {
        try
        {
            if (_keyboardProcess != null)
            {
                // Kill the keyboard process
                _keyboardProcess.Kill();
                _keyboardProcess.Dispose();
                _keyboardProcess = null;

                // Force kill any remaining keyboard processes
                var processKill = new Process
                {
                    StartInfo = new ProcessStartInfo
                    {
                        FileName = "killall",
                        Arguments = "-9 onboard matchbox-keyboard florence",  // Common Linux on-screen keyboards
                        UseShellExecute = false,
                        CreateNoWindow = true
                    }
                };
                processKill.Start();
                processKill.WaitForExit(1000);
                processKill.Dispose();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error closing keyboard: {ex.Message}");
        }
    }
    private void setDefaultSettings()
    {
        _mainWindow.minimizeBtn.IsVisible = false;

        var stackPanel = _mainWindow.HomeTrack.Parent as StackPanel;

        if (_isFromManualControl)
        {
            // Special UI setup when called from ManualControl
            _mainWindow.HomeTrack.IsVisible = true;
            _mainWindow.HomePolygon.Stroke = Avalonia.Media.Brushes.Black;
            _mainWindow.RecipeSelTrack.IsVisible = false;
            _mainWindow.RunInterfaceTrack.IsVisible = false;
            _mainWindow.RecipePanelTrack.IsVisible = true;
            _mainWindow.RecipePanelPolygon.Stroke = Avalonia.Media.Brushes.Black;
            _mainWindow.RecipeEditTrack.IsVisible = false;
            _mainWindow.SettingTrack.IsVisible = false;
            _mainWindow.AdvanceSettingsTrack.IsVisible = false;
            _mainWindow.ManualControlTrack.IsVisible = true;
            _mainWindow.ManualControlPolygon.Stroke = Avalonia.Media.Brushes.Black;
        }
        else
        {
            // Original logic for other callers
            //Set Track Up
            _mainWindow.HomeTrack.IsVisible = true;
            _mainWindow.HomePolygon.Stroke = Avalonia.Media.Brushes.Black;
            _mainWindow.RecipeSelTrack.IsVisible = false;
            _mainWindow.RunInterfaceTrack.IsVisible = false;
            _mainWindow.RecipePanelTrack.IsVisible = false;
            _mainWindow.RecipeEditTrack.IsVisible = false;
            if (_isAdvSetting)
            {
                _mainWindow.SettingTrack.IsVisible = false;
                _mainWindow.AdvanceSettingsTrack.IsVisible = true;
                _mainWindow.AdvanceSettingsPolygon.Stroke = Avalonia.Media.Brushes.Black;
            }
            else
            {
                _mainWindow.SettingTrack.IsVisible = true;
                _mainWindow.SettingPolygon.Stroke = Avalonia.Media.Brushes.Black;
                _mainWindow.AdvanceSettingsTrack.IsVisible = false;

            }
        }

        _mainWindow.DiagnosticsTrack.IsVisible = false;
        // Remove the button from its current position
        stackPanel.Children.Remove(_mainWindow.SoftwareTrack);

        // Add it back at the end of the StackPanel
        stackPanel.Children.Add(_mainWindow.SoftwareTrack);
        _mainWindow.SoftwareTrack.IsVisible = true;
        _mainWindow.SoftwarePolygon.Stroke = Brush.Parse("#A4275D");


        _mainWindow.TitleBtn.IsVisible = false;
        //Set Footer
        _mainWindow.footerMsg.IsVisible = false;
        _mainWindow.footer.Background = Brush.Parse("#f2f2f2");
        _mainWindow.footerDate.Text = DateTime.Now.ToString("dd/MM/yyyy");
        _mainWindow.footerTime.Text = DateTime.Now.ToString("hh:mm tt");
        _mainWindow.footerDateContainer.IsVisible = true;
        _mainWindow.footerStartBtn.IsVisible = false;
        _mainWindow.adminBtns.IsVisible = false;
    }

    private void showDefaultValues() 
    {
        var users = _user.ReadUsers();
        var allUIUsers = this.GetLogicalDescendants()
                   .OfType<TextBlock>()
                   .Where(cb => cb.Classes.Contains("user"))
                   .ToList();
        for (int i = 0; i < allUIUsers.Count; i++)
        {
            allUIUsers[i].Text = users[i].UserName;
        }
        var screenData = _screeen.ReadScreens()?[0];

        brightnessValue.Text = screenData?.brightness.ToString();
        dimValue.Text = (screenData?.dimSec/60.0).ToString();
        offValue.Text = (screenData?.offSec/60.0).ToString();

    }



  
}