using GMCabsDriverAssistant.Models;
using GMCabsDriverAssistant.Services;
using GMCabsDriverAssistant.Utils;
using GMCabsDriverAssistant.ViewModels;
using GMCabsDriverAssistantSolution.Views;
//using Plugin.BluetoothLE;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text;
using System.Threading;
//using Xamarin.CommunityToolkit.Extensions;
using Microsoft.Maui;
using Microsoft.Maui.Controls;
using GMCabsDriverAssistantSolution.ViewModels;

namespace GMCabsDriverAssistant.UserControl.ViewModels
{
    public delegate void BluetoothStatusChanged();

    class TripInformationViewModel : BaseViewModel
    {
        [Browsable(true)]
        [Category("Action")]
        [Description("Invoked when user clicks button")]
        public event BluetoothStatusChanged BluetoothStatusChanged;

        #region Fields
        private bool hasUnreadNotifications;
        public int seconds = 0;
        public string timerSeconds = "00:00:00";
        public string pickUpAddress = "";
        public string dropUpAddress = "";
        private bool isBookingAvailable;
        private string startTripButtonText;
        private bool visibleTrip;
        private string startSuburb;
        private bool isStartTripButtonVisible;
        private string pickUpDateTimeOrEndSuburb;

        //private List<IGattCharacteristic> Characteristics;
        private bool foundDevice = false;
        //private IAdapter adapter;

        public bool MeterTripStarted;
        private int lastMeterTripStatus = -1;
        private string startTimeOrEndLocation;
        private bool isOkButtonVisible = false;
        public int autocloseOkSecond = 30;
        Page _page;
        private int mainStackLayoutMargin;
        private int indicatorMargin;
        private int logoMargin;
        private bool isDummyButtonsVisible;
        private int controlsMargin;
        private int dummyButtonLayoutMargin;
        private bool duressReleased;
        private int duressSeconds;
        private string duressButtonText;
        private string bluetoothConnectionStatusText;
        private string imageIcon;
        private int topLayoutMargin;
        private int rightLayoutMargin;
        private bool isPlotButtonVisible;
        #endregion

        #region Properties
        public Command OnStartEndTripClick { get; }

        MeterTrip meterTrip = new MeterTrip();
        public ObservableCollection<BookingDto> Bookings { get; }
        public Command<BookingDto> BookingTapped { get; }
        public double CurrentLat { get; set; }
        public double CurrentLng { get; set; }
        public Location CurrentLocation { get; set; }
        public Command onStartTripClick { get; }
        public Command OnOkButtonClick { get; }
        public string StartTripButtonText
        {
            get => startTripButtonText;
            set => SetProperty(ref startTripButtonText, value);
        }
        public bool HasUnreadNotifications
        {
            get => hasUnreadNotifications;
            set => SetProperty(ref hasUnreadNotifications, value);
        }

        public string TimerSeconds
        {
            get => timerSeconds;
            set => SetProperty(ref timerSeconds, value);
        }
        public string PickUpAddress
        {
            get => pickUpAddress;
            set
            {
                SetProperty(ref pickUpAddress, value);
            }
        }
        public string DropUpAddress
        {
            get => dropUpAddress;
            set
            {
                SetProperty(ref dropUpAddress, value);
            }
        }
        public bool IsBookingAvailable
        {
            get => isBookingAvailable;
            set => SetProperty(ref isBookingAvailable, value);
        }

        public bool VisibleTrip
        {
            get => visibleTrip;
            set => SetProperty(ref visibleTrip, value);
        }
        public string StartSuburb
        {
            get => startSuburb;
            set
            {
                SetProperty(ref startSuburb, value);
            }
        }
        public bool IsStartTripButtonVisible
        {
            get => isStartTripButtonVisible;
            set => SetProperty(ref isStartTripButtonVisible, value);
        }
        public string PickUpDateTimeOrEndSuburb
        {
            get => pickUpDateTimeOrEndSuburb;
            set => SetProperty(ref pickUpDateTimeOrEndSuburb, value);
        }
        public Thickness MainStackLayoutMargin
        {
            get { return new Thickness(mainStackLayoutMargin, 0, mainStackLayoutMargin, 20); }
        }
        public Thickness IndicatorMargin
        {
            get { return new Thickness(0, indicatorMargin, 0, 0); }
        }
        public Thickness LogoMargin
        {
#if DEBUG
              get { return new Thickness(0, logoMargin, 0, 0); }
#else
              get { return new Thickness(logoMargin, 0 , 0, 0); }
#endif
        }
        public Thickness ImageLayoutMargin
        {
#if DEBUG
              get { return new Thickness(0, topLayoutMargin, rightLayoutMargin, 0); }
#else
              get { return new Thickness(0, topLayoutMargin, rightLayoutMargin, 0); }
#endif
        }
        public Thickness ControlsMargin
        {
            get { return new Thickness(0, controlsMargin, 0, 0); }
        }
        public Thickness DummyButtonLayoutMargin
        {
            get { return new Thickness(0, dummyButtonLayoutMargin, 0, 0); }
        }
        public bool IsDummyButtonsVisible
        {
            get => isDummyButtonsVisible;
            set
            {
                SetProperty(ref isDummyButtonsVisible, value);
            }
        }        
        public Command onCancelTripClick { get; }
        public Command OnMeterStartTripClick { get; }
        public Command OnMeterEndTripClick { get; }


        public string StartTimeOrEndLocation
        {
            get => startTimeOrEndLocation;
            set => SetProperty(ref startTimeOrEndLocation, value);
        }
        public bool IsOkButtonVisible
        {
            get => isOkButtonVisible;
            set => SetProperty(ref isOkButtonVisible, value);
        }

        public string BluetoothConnectionStatusText
        {
            get => bluetoothConnectionStatusText;
            set
            {
                SetProperty(ref bluetoothConnectionStatusText, value);
                BluetoothStatusChanged?.Invoke();
            }
        }
        public string DuressButtonText
        {
            get => duressButtonText;
            set
            {
                SetProperty(ref duressButtonText, value);
            }
        }
        public string ImageIcon
        {
            get => imageIcon;
            set
            {
                SetProperty(ref imageIcon, value);
            }
        }
        public bool IsPlotButtonVisible
        {
            get => isPlotButtonVisible;
            set => SetProperty(ref isPlotButtonVisible, value);
        }
        #endregion

        #region Constructor
        public TripInformationViewModel()
        {
            ContinuouslyShowAllPropertiesStatus();
            ShowStartTimerDuration(DispatchAppComponentService.isTripStarted);
            CountEndTripDuration(DispatchAppComponentService.isTripEndeded);
            lastMeterTripStatus = Preferences.Get("MeterTripStatus", 0);
            OnOkButtonClick = new Command(OnOkClick);
            OnStartEndTripClick = new Command(OnStartEndTripButtonClick);
            OnMeterStartTripClick = new Command(CallMeterStartTrip);
            OnMeterEndTripClick = new Command(MeterEndTrip);
            DuressButtonText = "!";

            CheckForConnectedMeter();

#if DEBUG
            mainStackLayoutMargin = 30;
            indicatorMargin = 5;
            logoMargin = 20;
            IsDummyButtonsVisible = true;
            controlsMargin = 20;
            dummyButtonLayoutMargin = 10;
            topLayoutMargin = -5;
            rightLayoutMargin = -15;
#else
            mainStackLayoutMargin = 30;
            indicatorMargin = 5;
            logoMargin = 20;
            IsDummyButtonsVisible = true;
            controlsMargin = 20;
            dummyButtonLayoutMargin = 10;
            topLayoutMargin = -5;
            rightLayoutMargin = -15;
#endif
        }

        #endregion

        #region Methods
        private void OnStartEndTripButtonClick(object obj)
        {
            ManageDriverTrip(false);
        }
        private void OnOkClick()
        {
            DispatchAppComponentService.OnOkClick();
            DispatchAppComponentService.isPlotButtonVisible = true;
            ShowAllPropertiesStatus();
        }
        private void MeterStartTrip()
        {
            // setting MeterTripStarted only here to ensure a manual trip does not get mistaken for a meter trip
            if (!MeterTripStarted)
            {
                StartTripButtonText = DispatchAppComponentService.MeterStartTrip();
                ManageDriverTrip(true);
            }
        }
        private void MeterEndTrip()
        {
            if (MeterTripStarted)
            {
                StartTripButtonText = DispatchAppComponentService.MeterEndTrip();
                ManageDriverTrip(true);
            }
        }
        public void StartDriverDuress()
        {
            duressReleased = false;
            duressSeconds = 0;
            bool hasVibrated = false;
            Device.StartTimer(TimeSpan.FromSeconds(1), () =>
            {
                duressSeconds++;
                if (duressSeconds > 2)
                {
                    if (!hasVibrated)
                    {
                        hasVibrated = true;
                        Vibration.Vibrate(TimeSpan.FromSeconds(1));
                    }   
                }

                if (duressReleased)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            });
        }
        public async void EndDriverDuress()
        {
            duressReleased = true;
            Vibration.Cancel();
            if (duressSeconds > 2)
            {
                var token = Preferences.Get(SecureStorageData.Token,"");
                GMCabsDriverService gmCabsDriverService = new GMCabsDriverService();

                var currentLocation = Geolocation.GetLastKnownLocationAsync();

                double currentLat = 0;
                double currentLng = 0;
                if (currentLocation != null && currentLocation.Result != null)
                {
                    currentLat = currentLocation.Result.Latitude;
                    currentLng = currentLocation.Result.Longitude;
                }

                await gmCabsDriverService.DriverDistress(token, currentLat, currentLng);

                DuressButtonText = "...";
                await System.Threading.Tasks.Task.Delay(2000);
                DuressButtonText = "!";
            }
        }
        private void ShowStartTimerDuration(bool isTripStarted)
        {
            seconds = DispatchAppComponentService.seconds;
            if (isTripStarted)
            {
                Device.StartTimer(TimeSpan.FromSeconds(1), () =>
                {
                    var meterRunningStatus = Preferences.Get("MeterRunningStatus", "");
                    if (meterRunningStatus == "Running")
                    {
                        Device.BeginInvokeOnMainThread(() =>
                        {
                            ++seconds;
                            DispatchAppComponentService.StartTrip(seconds);
                            TimerSeconds = DispatchAppComponentService.timerSeconds;
                            DispatchAppComponentService.seconds = seconds;
                        });
                    }
                    if (meterRunningStatus == "Running")
                        return true;
                    else
                        return false;
                });

            }
        }
        private void CountEndTripDuration(bool isTripEnded)
        {
            autocloseOkSecond = DispatchAppComponentService.autocloseOkSecond;
            if (isTripEnded)
            {
                Device.StartTimer(TimeSpan.FromSeconds(1), () =>
                {
                    var meterRunningStatus = Preferences.Get("MeterRunningStatus", "");
                    if (meterRunningStatus == "Stopped")
                    {
                        if (autocloseOkSecond == 0)
                        {
                            Device.BeginInvokeOnMainThread(() =>
                            {                                
                                OnOkClick();
                            });
                        }
                        else
                        {
                            --autocloseOkSecond;
                            DispatchAppComponentService.autocloseOkSecond = autocloseOkSecond;
                        }
                    }
                    if (meterRunningStatus == "Stopped")
                        return true;
                    else
                        return false;
                });
            }
        }
        private void ShowAllPropertiesStatus()
        {
            ImageIcon = DispatchAppComponentService.imageIcon;
            IsStartTripButtonVisible = DispatchAppComponentService.isStartTripButtonVisible;
            IsPlotButtonVisible = DispatchAppComponentService.isPlotButtonVisible;
            StartTripButtonText = DispatchAppComponentService.startTripButtonText;
            MeterTripStarted = DispatchAppComponentService.meterTripStarted;
            VisibleTrip = DispatchAppComponentService.visibleTrip;
            StartSuburb = DispatchAppComponentService.startSuburb;
            PickUpDateTimeOrEndSuburb = DispatchAppComponentService.pickUpDateTimeOrEndSuburb;
            StartTimeOrEndLocation = DispatchAppComponentService.startTimeOrEndLocation;
            IsOkButtonVisible = DispatchAppComponentService.isOkButtonVisible;
            TimerSeconds = DispatchAppComponentService.timerSeconds;
        }        
        private void ContinuouslyShowAllPropertiesStatus()
        {

            Device.StartTimer(TimeSpan.FromSeconds(1), () =>
            {
                Device.BeginInvokeOnMainThread(() =>
                      {
                          ShowAllPropertiesStatus();
                      });
                return true;
            });
        }
        public void SetTripStartEndButtonPosition()
        {
            DispatchAppComponentService.isPlotButtonVisible= false;
            ShowAllPropertiesStatus();
        }
        #endregion

        #region Trip Handling
        private void ManageDriverTrip(bool fromMeter)
        {
            if (StartTripButtonText.Equals("START TRIP"))
            {
                DispatchAppComponentService.isTripStarted = true;
                DispatchAppComponentService.isTripEndeded = false;
                DispatchAppComponentService.ManageDriverTrip(fromMeter);
                StartTimeOrEndLocation = DispatchAppComponentService.startTimeOrEndLocation;
                StartTrip(fromMeter);
                TimerSeconds = DispatchAppComponentService.timerSeconds;
                DispatchAppComponentService.seconds = seconds = 0;
                ShowStartTimerDuration(DispatchAppComponentService.isTripStarted);
                DispatchAppComponentService.isPlotButtonVisible = false;
            }
            else if (StartTripButtonText.Equals("DROP OFF"))
            {
                DispatchAppComponentService.isTripStarted = false;
                DispatchAppComponentService.isTripEndeded = true;
                DispatchAppComponentService.ManageDriverTrip(fromMeter);
                StartTimeOrEndLocation = DispatchAppComponentService.startTimeOrEndLocation;
                EndTrip(fromMeter);
                IsOkButtonVisible = DispatchAppComponentService.isOkButtonVisible;
                DispatchAppComponentService.autocloseOkSecond = autocloseOkSecond = 30;
                CountEndTripDuration(DispatchAppComponentService.isTripEndeded);
            }
        }
        private async void StartTrip(bool fromMeter)
        {
            DispatchAppComponentService.startSuburb = await DispatchAppComponentService.GetSuburbName(fromMeter, true);
            MeterTripStarted = DispatchAppComponentService.meterTripStarted;
            ImageIcon = DispatchAppComponentService.imageIcon;
            VisibleTrip = DispatchAppComponentService.visibleTrip;
            StartSuburb = DispatchAppComponentService.startSuburb;
            PickUpDateTimeOrEndSuburb = DispatchAppComponentService.pickUpDateTimeOrEndSuburb;
            StartTripButtonText = DispatchAppComponentService.startTripButtonText;
        }
        private async void EndTrip(bool fromMeter)
        {
            DispatchAppComponentService.pickUpDateTimeOrEndSuburb = await DispatchAppComponentService.GetSuburbName(fromMeter, false);
            MeterTripStarted = DispatchAppComponentService.meterTripStarted;
            PickUpDateTimeOrEndSuburb = DispatchAppComponentService.pickUpDateTimeOrEndSuburb;
            ImageIcon = DispatchAppComponentService.imageIcon;
            IsStartTripButtonVisible = DispatchAppComponentService.isStartTripButtonVisible;
        }
        private void CallMeterStartTrip()
        {            
            DispatchAppComponentService.startTripButtonText = "START TRIP";
            DispatchAppComponentService.meterTripStarted = false;
            DispatchAppComponentService.isTripStarted = true;
            DispatchAppComponentService.isTripEndeded = false;
            DispatchAppComponentService.isOkButtonVisible = false;
            DispatchAppComponentService.isStartTripButtonVisible = true;
            DispatchAppComponentService.ManageDriverTrip(false);
            StartTimeOrEndLocation = DispatchAppComponentService.startTimeOrEndLocation;
            StartTrip(false);
            TimerSeconds = DispatchAppComponentService.timerSeconds;
            DispatchAppComponentService.seconds = seconds = 0;
            ShowStartTimerDuration(DispatchAppComponentService.isTripStarted);
        }
        #endregion Trip Handling

        #region Meter Handling

        private void CheckForConnectedMeter()
        {
           // ConnectToMeter();
        }
        //private void ConnectToMeter()
        //{
        //    adapter = CrossBleAdapter.Current;
        //    var status = adapter.Status.ToString();

        //    if (status.Contains("Off"))
        //    {
        //        bluetoothConnectionStatusText = "Bluetooth connection off...";
        //    }
        //    else
        //    {
        //        BluetoothConnectionStatusText = "Checking meter connection...";
        //        BluetoothConnectionStatusText = $"Adapter status {CrossBleAdapter.Current.Status.ToString()}";

        //        IDevice bondedDevice = null;



        //        CrossBleAdapter.Current.GetConnectedDevices().Subscribe(deviceResult =>
        //        {
        //            bondedDevice = deviceResult.GetEnumerator().Current;
        //        });
        //        if (bondedDevice != null && bondedDevice.Status == ConnectionStatus.Connected)
        //        {
        //            ListenForCharacteristic(bondedDevice);
        //        }
        //        else
        //        {
        //            CrossBleAdapter.Current.GetPairedDevices().Subscribe(devices =>
        //            {
        //                if (devices != null)
        //                {
        //                    ConnectionConfig conConfig = new ConnectionConfig();
        //                    conConfig.AutoConnect = true;

        //                    BluetoothConnectionStatusText = $"Listening for paired device";

        //                    foreach (var pairedDevice in devices)
        //                    {
        //                        pairedDevice.ConnectWait(conConfig).Subscribe(device =>
        //                        {
        //                            Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { BluetoothConnectionStatusText = $"{device.Status}"; });
        //                            ListenForCharacteristic(pairedDevice);
        //                        });
        //                    }
        //                }
        //            });

        //            if (CrossBleAdapter.Current.IsScanning)
        //            {
        //                BluetoothConnectionStatusText = $"resuming scan";
        //            }
        //            else
        //            {
        //                BluetoothConnectionStatusText = $"Adapter status {CrossBleAdapter.Current.Status.ToString()} - Scanning";
        //                Characteristics = new List<IGattCharacteristic>();
        //                var scanResult = CrossBleAdapter.Current.Scan().Subscribe(scResult => { CheckDevice(scResult); }, exception =>
        //                {
        //                    Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { BluetoothConnectionStatusText = $"Error: {exception.Message}"; });
        //                });
        //            }
        //        }
        //    }
        //}
        //private void CheckDevice(IScanResult scanResult)
        //{
        //    if (scanResult.Device.Name != null && scanResult.Device.Name.StartsWith("MTI_") && !foundDevice)
        //    {
        //        BluetoothConnectionStatusText = $"Meter found -  {scanResult.Device.Name}";
        //        foundDevice = true;

        //        CrossBleAdapter.Current.StopScan();
        //        ConnectToDevice(scanResult.Device);
        //    }
        //}
        //private void ConnectToDevice(IDevice discoveredDevice)
        //{
        //    ConnectionConfig conConfig = new ConnectionConfig();
        //    conConfig.AutoConnect = true;

        //    Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { BluetoothConnectionStatusText = $"Device Details -  P:{discoveredDevice.PairingStatus.ToString()} - C:{discoveredDevice.IsConnected()}"; });

        //    if (discoveredDevice.IsConnected())
        //    {
        //        Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { BluetoothConnectionStatusText = $"Searching for GUIDs"; });
        //        ListenForCharacteristic(discoveredDevice);
        //    }
        //    else
        //    {
        //        if (discoveredDevice.PairingStatus == PairingStatus.NotPaired)
        //        {
        //            Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { BluetoothConnectionStatusText = $"Pairing"; });
        //            discoveredDevice.PairingRequest("191135");
        //        }
        //        Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { BluetoothConnectionStatusText = $"Connecting"; });
        //        discoveredDevice.ConnectWait(conConfig).Subscribe(device =>
        //        {
        //            Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { BluetoothConnectionStatusText = $"{device.Status}"; });
        //            ListenForCharacteristic(device);
        //        });
        //    }
        //}
        //private void ListenForCharacteristic(IDevice device)
        //{
        //    bool subscribed = false;
        //    try
        //    {
        //        device.GetKnownCharacteristics(Guid.Parse("de201840-063f-11e5-be3e-0002a5d5c51b"), new Guid[] { Guid.Parse("de000180-063f-11e5-9e69-0002a5d5c503") }).Subscribe(characteristics =>
        //        {
        //            Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { BluetoothConnectionStatusText = $"Service Detected"; });
        //            if (characteristics != null)
        //            {
        //                characteristics.RegisterAndNotify().Subscribe(registerResult =>
        //                {
        //                // RegisterAndNotify seems to keep firing each time, there must be a better way
        //                // to do this only once, currently just setting a local flag.
        //                    if (!subscribed)
        //                    {
        //                        Xamarin.Forms.Device.BeginInvokeOnMainThread(() =>
        //                        {
        //                            BluetoothConnectionStatusText = "Ready";
        //                        });
        //                        subscribed = true;
        //                        characteristics.WhenNotificationReceived().Subscribe(notification => { CheckNotification(notification); });
        //                    }
        //                });
        //            }
        //        });
        //    }
        //    catch(Exception ex)
        //    {

        //    }
        //}
        //private void CheckNotification(CharacteristicGattResult notification)
        //{
        //    if (notification != null && notification.Data != null && notification.Characteristic != null && notification.Characteristic.Uuid.ToString() == "de000180-063f-11e5-9e69-0002a5d5c503")
        //    {
        //        string data = $"Date:{DateTime.Now.ToString("HH:mm:ss")}, Description:{notification.Characteristic.Uuid},Data:{BitConverter.ToString(notification.Data)}\n";
        //        Xamarin.Forms.Device.BeginInvokeOnMainThread(() =>
        //        {
        //            int tripStatus = 0;
        //            if (notification.Data[0] != 0) { tripStatus = 1; }
        //            if (lastMeterTripStatus != tripStatus)
        //            {
        //                lastMeterTripStatus = tripStatus;
        //                Preferences.Set("MeterTripStatus", tripStatus);
        //                if (tripStatus == 0)
        //                {
        //                    MeterEndTrip();
        //                }
        //                else if (tripStatus == 1)
        //                {
        //                    //MeterStartTrip();
        //                    CallMeterStartTrip();
        //                }           
        //            }
        //        });

        //    }
        //}

        #endregion Meter Handling
    }
}
