using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Wino.Core.Domain;
using Wino.Core.Domain.Entities.Mail;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Folders;
using Wino.Core.Domain.Models.Navigation;
using Wino.Mail.ViewModels.Data;
namespace Wino.Mail.ViewModels;
///
/// Backs the per-account Folder Customization page — lets the user reorder,
/// pin/unpin, and hide folders for a single real (non-merged) account.
///
public partial class FolderCustomizationPageViewModel : MailBaseViewModel
{
private readonly IMailDialogService _dialogService;
private readonly IFolderService _folderService;
private readonly IAccountService _accountService;
private static readonly SpecialFolderType[] GmailCategorySubTypes =
[
SpecialFolderType.Promotions,
SpecialFolderType.Social,
SpecialFolderType.Updates,
SpecialFolderType.Forums,
SpecialFolderType.Personal
];
private Guid _accountId;
private bool _isLoaded;
[ObservableProperty]
public partial string AccountName { get; set; }
[ObservableProperty]
public partial bool IsGmailAccount { get; set; }
public ObservableCollection PinnedFolders { get; } = [];
public ObservableCollection CategoryFolders { get; } = [];
public ObservableCollection MoreFolders { get; } = [];
public FolderCustomizationPageViewModel(IMailDialogService dialogService,
IFolderService folderService,
IAccountService accountService)
{
_dialogService = dialogService;
_folderService = folderService;
_accountService = accountService;
}
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
{
base.OnNavigatedTo(mode, parameters);
if (parameters is not Guid accountId)
return;
_accountId = accountId;
var account = await _accountService.GetAccountAsync(accountId);
if (account == null) return;
AccountName = account.Name;
IsGmailAccount = account.ProviderType == MailProviderType.Gmail;
await LoadFoldersAsync();
_isLoaded = true;
}
private async Task LoadFoldersAsync()
{
PinnedFolders.Clear();
CategoryFolders.Clear();
MoreFolders.Clear();
var allFolders = await _folderService.GetFoldersAsync(_accountId);
// Skip the Gmail "Categories" virtual bucket entity — Categories are rendered
// as an inline section, not as a regular folder row.
foreach (var folder in allFolders.Where(f => f.SpecialFolderType != SpecialFolderType.Category))
{
var item = new FolderCustomizationItemViewModel(folder);
if (IsGmailAccount && GmailCategorySubTypes.Contains(folder.SpecialFolderType))
{
CategoryFolders.Add(item);
}
else if (folder.IsSticky)
{
PinnedFolders.Add(item);
}
else
{
MoreFolders.Add(item);
}
}
}
[RelayCommand]
private async Task ResetAsync()
{
var confirmed = await _dialogService.ShowConfirmationDialogAsync(
Translator.FolderCustomization_ResetConfirmMessage,
Translator.FolderCustomization_ResetConfirmTitle,
Translator.FolderCustomization_Reset);
if (!confirmed) return;
await _folderService.ResetFolderCustomizationAsync(_accountId);
await LoadFoldersAsync();
}
///
/// Called by the view after a drag-reorder or pin/unpin change. Persists the
/// complete new layout and hidden state for this account.
///
public async Task PersistLayoutAsync()
{
if (!_isLoaded) return;
// Reconcile IsSticky: Pinned rows become sticky, everything in More loses sticky.
// Categories (Gmail virtual group children) keep their own rules.
var touchedFolders = new List();
foreach (var item in PinnedFolders)
{
if (!item.Folder.IsSticky)
{
item.Folder.IsSticky = true;
touchedFolders.Add(item.Folder);
}
}
foreach (var item in MoreFolders)
{
if (item.Folder.IsSticky)
{
item.Folder.IsSticky = false;
touchedFolders.Add(item.Folder);
}
}
foreach (var folder in touchedFolders)
{
await _folderService.ChangeStickyStatusAsync(folder.Id, folder.IsSticky);
}
// Persist the new order: Pinned first, then Categories, then More. The
// concrete number assigned is only meaningful relative to others in the
// same account; we still number them globally for simplicity.
var orderedIds = new List();
orderedIds.AddRange(PinnedFolders.Select(a => a.Folder.Id));
orderedIds.AddRange(CategoryFolders.Select(a => a.Folder.Id));
orderedIds.AddRange(MoreFolders.Select(a => a.Folder.Id));
await _folderService.UpdateFolderOrdersAsync(_accountId, orderedIds);
}
public async Task ToggleHiddenAsync(FolderCustomizationItemViewModel item)
{
if (item == null) return;
item.IsHidden = !item.IsHidden;
item.Folder.IsHidden = item.IsHidden;
await _folderService.ChangeFolderHiddenStatusAsync(item.Folder.Id, item.IsHidden);
}
public async Task TogglePinAsync(FolderCustomizationItemViewModel item)
{
if (item == null) return;
// Categories sub-items cannot be pinned individually; they always travel
// with the virtual Categories group.
if (CategoryFolders.Contains(item)) return;
if (PinnedFolders.Contains(item))
{
PinnedFolders.Remove(item);
MoreFolders.Insert(0, item);
}
else if (MoreFolders.Contains(item))
{
MoreFolders.Remove(item);
PinnedFolders.Add(item);
}
await PersistLayoutAsync();
}
}