using Dapper;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;
using Sonex.Client.Dialogs;
using Sonex.Client.Helpers;
using Sonex.Client.Layouts;
using Sonex.Client.Models;
using Sonex.DBWrapper;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;

namespace Sonex.Client.Pages.Administrator.Accounts;

public sealed partial class Accounts : Page
{
    public ObservableCollection<ItemsAndContentListItem> AccountItems { get; } = new();

    public AccountModel? SelectedAccount { get; set; }

    public bool isSelectedAccount => _Layout.SelectedItemId !=null;
    private bool _isProgrammaticChange;

    public Accounts()
    {
        InitializeComponent();
    }

    private async void Layout_Loaded(object sender, RoutedEventArgs e)
    {
        await LoadList();
    }

    public async Task LoadList(long? preferredAccountId = null)
    {
        _isProgrammaticChange = true;

        try
        {
            var result = await AccountModel.GetAll();
            if (!result.Success)
            {
                await this.ShowMessageAsync(result);
                return;
            }

            AccountItems.Clear();

            foreach (var item in result.Items
                                       .OrderBy(x => x.FullName)
                                       .ThenBy(x => x.AccountName))
            {
                AccountItems.Add(CreateListItem(item));
            }

            long? selectedId = preferredAccountId;

            if (!selectedId.HasValue && SelectedAccount != null && SelectedAccount.Id > 0)
                selectedId = SelectedAccount.Id;

            if (!selectedId.HasValue)
                selectedId = AccountItems.FirstOrDefault()?.Id;

            _Layout.SelectedItemId = selectedId;

            if (selectedId.HasValue)
                await LoadSelectedAccountAsync(selectedId.Value);
            else
                ClearSelectedAccountView();
        }
        finally
        {
            _isProgrammaticChange = false;
        }
    }

    public async Task LoadSelectedAccountAsync(long accountId)
    {
        _isProgrammaticChange = true;

        try
        {
            var selectedListItem = AccountItems.FirstOrDefault(x => x.Id == accountId);
            if (selectedListItem == null || string.IsNullOrWhiteSpace(selectedListItem.Key))
            {
                ClearSelectedAccountView();
                return;
            }

            var result = await AccountModel.Get(selectedListItem.Key);
            var groupsResult = await AccountModel.GetAllGroups();

            PermissionsControl.ItemsSource = groupsResult.Success
                ? groupsResult.Items
                : null;

            if (result.Success && result.Item != null)
            {
                SelectedAccount = result.Item;
                PermissionsControl.SelectedItems = result.Item.Groups.AsList();
                UpdateSelectedListItemFromSelectedAccount();
            }
            else
            {
                await this.ShowErrorAsync("Error", result?.ErrorMessage ?? "");
                SelectedAccount = new AccountModel();
                PermissionsControl.SelectedItems = [];
            }

            Bindings.Update();
        }
        finally
        {
            _isProgrammaticChange = false;
        }
    }

    private void ClearSelectedAccountView()
    {
        SelectedAccount = new AccountModel();
        PermissionsControl.ItemsSource = null;
        PermissionsControl.SelectedItems = [];
        Bindings.Update();
    }

    private static ItemsAndContentListItem CreateListItem(AccountModel account)
    {
        return new ItemsAndContentListItem
        {
            Id = account.Id,
            Key = account.AccountName ?? string.Empty,
            Title = account.FullName ?? string.Empty,
            Subtitle = account.Department ?? string.Empty,
            Description = account.AccountName ?? string.Empty,
            SearchText = BuildSearchText(account),
            IsEnabled = account.IsEnabled,
            Picture = null,
            ShowPicture = false
            
        };
    }

    private static string BuildSearchText(AccountModel account)
    {
        return string.Join(" ",
        [
            account.AccountName ?? string.Empty,
            account.FullName ?? string.Empty,
            account.FirstName ?? string.Empty,
            account.LastName ?? string.Empty,
            account.Department ?? string.Empty,
            account.AccountLocusWms ?? string.Empty,
            account.AccountLocusTerminal ?? string.Empty
        ]);
    }

    private void UpdateSelectedListItemFromSelectedAccount()
    {
        if (SelectedAccount == null || SelectedAccount.Id <= 0)
            return;

        var item = AccountItems.FirstOrDefault(x => x.Id == SelectedAccount.Id);
        if (item == null)
            return;
        item.Id = SelectedAccount.Id;
        item.Key = SelectedAccount.AccountName ?? string.Empty;
        item.Title = SelectedAccount.FullName ?? string.Empty;
        item.Subtitle = SelectedAccount.Department ?? string.Empty;
        item.Description = SelectedAccount.AccountName ?? string.Empty;
        item.SearchText = BuildSearchText(SelectedAccount);
        item.IsEnabled = SelectedAccount.IsEnabled;
    }

    private async void Layout_SelectedItemChanged(object? sender, SelectedItemChangedEventArgs e)
    {
        if (_isProgrammaticChange)
            return;

        if (!e.NewId.HasValue)
        {
            ClearSelectedAccountView();
            return;
        }

        await LoadSelectedAccountAsync(e.NewId.Value);
    }

    private async void Layout_AddClicked(object sender, RoutedEventArgs e)
    {
        var dialog = new CreateNewAccountDialog
        {
            XamlRoot = Content.XamlRoot
        };

        dialog.UpdateLayout();

        var result = await dialog.ShowAsync();

        if (dialog.AccountId > -1)
        {
            Debug.WriteLine("ContentDialogResult.Primary");
            await LoadList(dialog.AccountId);
        }
    }

    private async void Layout_DeleteClicked(object sender, RoutedEventArgs e)
    {
        if (SelectedAccount == null || string.IsNullOrWhiteSpace(SelectedAccount.AccountName))
            return;

        var confirm = new ContentDialog
        {
            XamlRoot = Content.XamlRoot,
            Title = "Delete account",
            Content = $"Are you sure you want to delete account '{SelectedAccount.AccountName}'?",
            PrimaryButtonText = "Delete",
            CloseButtonText = "Cancel",
            DefaultButton = ContentDialogButton.Close
        };

        var result = await confirm.ShowAsync();
        if (result != ContentDialogResult.Primary)
            return;

        var deleteResult = await AccountModel.Delete(SelectedAccount.AccountName);
        await this.ShowMessageAsync(deleteResult);
        if (deleteResult.Success)
            await LoadList();
    }

    private async void ChangePassword_Click(object sender, RoutedEventArgs e)
    {
        if (SelectedAccount == null || string.IsNullOrWhiteSpace(SelectedAccount.AccountName))
            return;

        var dialog = new ChangePasswordDialog
        {
            XamlRoot = Content.XamlRoot
        };

        var result = await dialog.ShowAsync();
        if (result == ContentDialogResult.Primary)
        {
            var r = await AccountModel.ChangePasswordAsync(SelectedAccount.AccountName, dialog.Password);
            await this.ShowMessageAsync(r);
        }
    }

    private async void LoginAccess_Toggled(object sender, RoutedEventArgs e)
    {
        if (_isProgrammaticChange)
            return;

        if (sender is not ToggleSwitch toggle)
            return;

        if (SelectedAccount == null || string.IsNullOrWhiteSpace(SelectedAccount.AccountName))
            return;

        DB.SingleResult<bool>? result = toggle.IsOn
            ? await AccountModel.EnableAsync(SelectedAccount.AccountName)
            : await AccountModel.DisableAsync(SelectedAccount.AccountName);

        await this.ShowMessageAsync(result);

        if (result == null || !result.Success)
        {
            _isProgrammaticChange = true;
            try
            {
                toggle.IsOn = !toggle.IsOn;
            }
            finally
            {
                _isProgrammaticChange = false;
            }
        }
        else
        {
            UpdateSelectedListItemFromSelectedAccount();
        }
    }

    private async void SavePersonalInformation_Click(object sender, RoutedEventArgs e)
    {
        if (SelectedAccount == null)
            return;

        var result = await AccountModel.UpdatePersonalInformation(SelectedAccount);
        await this.ShowMessageAsync(result);

        if (result.Success)
        {
            UpdateSelectedListItemFromSelectedAccount();
            Bindings.Update();
        }
    }

    private async void SaveLinkedAccounts_Click(object sender, RoutedEventArgs e)
    {
        if (SelectedAccount == null)
            return;

        var result = await AccountModel.UpdateLinkedAccounts(SelectedAccount);
        await this.ShowMessageAsync(result);

        if (result.Success)
        {
            UpdateSelectedListItemFromSelectedAccount();
            Bindings.Update();
        }
    }

    private async void PermissionsControl_ItemChecked(object sender, Controls.CheckBoxChangedEventArgs e)
    {
        if (_isProgrammaticChange)
            return;

        if (SelectedAccount == null || string.IsNullOrWhiteSpace(SelectedAccount.AccountName))
            return;

        var result = await AccountModel.AddPermission(SelectedAccount.AccountName, e.Item);
        await this.ShowMessageAsync(result);
    }

    private async void PermissionsControl_ItemUnchecked(object sender, Controls.CheckBoxChangedEventArgs e)
    {
        if (_isProgrammaticChange)
            return;

        if (SelectedAccount == null || string.IsNullOrWhiteSpace(SelectedAccount.AccountName))
            return;

        var result = await AccountModel.RemovePermission(SelectedAccount.AccountName, e.Item);
        await this.ShowMessageAsync(result);
    }
}