using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using Serilog;
using Wino.Core.Domain;
using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Accounts;
using Wino.Core.Domain.Models.Calendar;
using Wino.Core.Domain.Exceptions;
using Wino.Core.Domain.Models.Navigation;
using Wino.Core.Domain.Models.Synchronization;
using Wino.Core.Services;
using Wino.Mail.ViewModels.Data;
using Wino.Messaging.Client.Navigation;
using Wino.Messaging.UI;

namespace Wino.Mail.ViewModels;

public partial class AccountSetupProgressPageViewModel : MailBaseViewModel
{
    private readonly IAccountService _accountService;
    private readonly ISpecialImapProviderConfigResolver _specialImapProviderConfigResolver;
    private readonly ICalDavClient _calDavClient;
    private readonly IMailDialogService _dialogService;

    public WelcomeWizardContext WizardContext { get; }

    public ObservableCollection<AccountSetupStepModel> Steps { get; } = [];

    [ObservableProperty]
    public partial bool IsSetupComplete { get; set; }

    [ObservableProperty]
    public partial bool IsSetupFailed { get; set; }

    [ObservableProperty]
    public partial string FailureMessage { get; set; }

    private MailAccount _createdAccount;
    private bool _dbWritten;

    public AccountSetupProgressPageViewModel(
        IAccountService accountService,
        ISpecialImapProviderConfigResolver specialImapProviderConfigResolver,
        ICalDavClient calDavClient,
        IMailDialogService dialogService,
        WelcomeWizardContext wizardContext)
    {
        _accountService = accountService;
        _specialImapProviderConfigResolver = specialImapProviderConfigResolver;
        _calDavClient = calDavClient;
        _dialogService = dialogService;
        WizardContext = wizardContext;
    }

    public override async void OnNavigatedTo(NavigationMode mode, object parameters)
    {
        base.OnNavigatedTo(mode, parameters);

        // Only run on fresh navigation, not on back-navigation
        if (mode == NavigationMode.Back) return;

        await RunSetupAsync();
    }

    private void BuildSteps()
    {
        Steps.Clear();

        if (WizardContext.IsOAuthProvider)
        {
            Steps.Add(new AccountSetupStepModel
            {
                Title = string.Format(Translator.AccountSetup_Step_Authenticating, WizardContext.SelectedProvider.Name)
            });
            Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_FetchingProfile });
            Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_SavingAccount });
            Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_SyncingFolders });
            Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_FetchingCalendarMetadata });
            Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_SyncingAliases });
            Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_Finalizing });
        }
        else if (WizardContext.IsSpecialImapProvider)
        {
            Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_TestingMailAuth });

            if (WizardContext.CalendarSupportMode == ImapCalendarSupportMode.CalDav)
            {
                Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_DiscoveringCalDav });
                Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_TestingCalendarAuth });
            }

            Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_SavingAccount });
            Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_SyncingFolders });

            if (WizardContext.CalendarSupportMode != ImapCalendarSupportMode.Disabled)
            {
                Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_FetchingCalendarMetadata });
            }

            Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_Finalizing });
        }
        else // Generic IMAP
        {
            Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_SavingAccount });
            Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_SyncingFolders });

            var setupResult = WizardContext.ImapCalDavSetupResult;
            if (setupResult?.IsCalendarAccessGranted == true &&
                setupResult.ServerInformation?.CalendarSupportMode == ImapCalendarSupportMode.CalDav)
            {
                Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_DiscoveringCalDav });
                Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_TestingCalendarAuth });
            }

            if (setupResult?.IsCalendarAccessGranted == true)
            {
                Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_FetchingCalendarMetadata });
            }

            Steps.Add(new AccountSetupStepModel { Title = Translator.AccountSetup_Step_Finalizing });
        }
    }

    private int _currentStepIndex;

    private void SetStepInProgress(string title)
    {
        for (int i = 0; i < Steps.Count; i++)
        {
            if (Steps[i].Title == title)
            {
                _currentStepIndex = i;
                Steps[i].Status = AccountSetupStepStatus.InProgress;
                return;
            }
        }
    }

    private void SetCurrentStepSucceeded()
    {
        if (_currentStepIndex < Steps.Count)
            Steps[_currentStepIndex].Status = AccountSetupStepStatus.Succeeded;
    }

    private void SetCurrentStepFailed(string errorMessage)
    {
        if (_currentStepIndex < Steps.Count)
        {
            Steps[_currentStepIndex].Status = AccountSetupStepStatus.Failed;
            Steps[_currentStepIndex].ErrorMessage = errorMessage;
        }
    }

    private async Task RunSetupAsync()
    {
        IsSetupComplete = false;
        IsSetupFailed = false;
        FailureMessage = null;
        _dbWritten = false;
        _createdAccount = null;

        BuildSteps();

        try
        {
            CustomServerInformation customServerInformation = null;

            // Build account in memory
            _createdAccount = new MailAccount
            {
                Id = Guid.NewGuid(),
                ProviderType = WizardContext.SelectedProvider.Type,
                Name = WizardContext.AccountName,
                SpecialImapProvider = WizardContext.SelectedProvider.SpecialImapProvider,
                AccountColorHex = WizardContext.AccountColorHex,
                IsCalendarAccessGranted = true
            };

            if (WizardContext.IsOAuthProvider)
            {
                // Step: Authenticating
                SetStepInProgress(string.Format(Translator.AccountSetup_Step_Authenticating, WizardContext.SelectedProvider.Name));

                var authTokenInfo = await SynchronizationManager.Instance.HandleAuthorizationAsync(
                    WizardContext.SelectedProvider.Type,
                    _createdAccount,
                    _createdAccount.ProviderType == MailProviderType.Gmail);

                _createdAccount.Address = authTokenInfo.AccountAddress;
                SetCurrentStepSucceeded();

                // Step: Save to DB
                SetStepInProgress(Translator.AccountSetup_Step_SavingAccount);
                await _accountService.CreateAccountAsync(_createdAccount, null);
                _dbWritten = true;
                SetCurrentStepSucceeded();

                // Step: Profile
                SetStepInProgress(Translator.AccountSetup_Step_FetchingProfile);
                var profileResult = await SynchronizationManager.Instance.SynchronizeProfileAsync(_createdAccount.Id);
                if (profileResult.CompletedState != SynchronizationCompletedState.Success)
                    throw new Exception(Translator.Exception_FailedToSynchronizeProfileInformation);

                if (profileResult.ProfileInformation != null)
                {
                    _createdAccount.SenderName = profileResult.ProfileInformation.SenderName;
                    _createdAccount.Base64ProfilePictureData = profileResult.ProfileInformation.Base64ProfilePictureData;

                    if (!string.IsNullOrEmpty(profileResult.ProfileInformation.AccountAddress))
                        _createdAccount.Address = profileResult.ProfileInformation.AccountAddress;

                    await _accountService.UpdateProfileInformationAsync(_createdAccount.Id, profileResult.ProfileInformation);
                }
                SetCurrentStepSucceeded();

                // Step: Folders
                SetStepInProgress(Translator.AccountSetup_Step_SyncingFolders);
                var folderResult = await SynchronizationManager.Instance.SynchronizeFoldersAsync(_createdAccount.Id);
                if (folderResult == null || folderResult.CompletedState != SynchronizationCompletedState.Success)
                    throw new Exception(Translator.Exception_FailedToSynchronizeFolders);
                SetCurrentStepSucceeded();

                // Step: Calendar metadata
                SetStepInProgress(Translator.AccountSetup_Step_FetchingCalendarMetadata);
                if (_createdAccount.IsCalendarAccessGranted)
                {
                    var calResult = await SynchronizationManager.Instance.SynchronizeCalendarAsync(new CalendarSynchronizationOptions
                    {
                        AccountId = _createdAccount.Id,
                        Type = CalendarSynchronizationType.CalendarMetadata
                    });
                    if (calResult == null || calResult.CompletedState != SynchronizationCompletedState.Success)
                        throw new Exception(Translator.Exception_FailedToSynchronizeCalendarMetadata);
                }
                SetCurrentStepSucceeded();

                // Step: Aliases
                SetStepInProgress(Translator.AccountSetup_Step_SyncingAliases);
                if (_createdAccount.IsAliasSyncSupported)
                {
                    var aliasResult = await SynchronizationManager.Instance.SynchronizeAliasesAsync(_createdAccount.Id);
                    if (aliasResult.CompletedState != SynchronizationCompletedState.Success)
                        throw new Exception(Translator.Exception_FailedToSynchronizeAliases);
                }
                else
                {
                    await _accountService.CreateRootAliasAsync(_createdAccount.Id, _createdAccount.Address);
                }
                SetCurrentStepSucceeded();
            }
            else if (WizardContext.IsSpecialImapProvider)
            {
                var dialogResult = WizardContext.BuildAccountCreationDialogResult();

                customServerInformation = _specialImapProviderConfigResolver.GetServerInformation(_createdAccount, dialogResult);
                if (customServerInformation == null) throw new Exception("Failed to resolve server information.");

                customServerInformation.Id = Guid.NewGuid();
                customServerInformation.AccountId = _createdAccount.Id;

                _createdAccount.Address = WizardContext.EmailAddress;
                _createdAccount.SenderName = WizardContext.DisplayName;
                _createdAccount.IsCalendarAccessGranted = customServerInformation.CalendarSupportMode != ImapCalendarSupportMode.Disabled;
                _createdAccount.ServerInformation = customServerInformation;

                // Step: Test IMAP
                SetStepInProgress(Translator.AccountSetup_Step_TestingMailAuth);
                await ValidateImapConnectivityAsync(customServerInformation);
                SetCurrentStepSucceeded();

                // Step: CalDAV discovery and testing (if applicable)
                if (customServerInformation.CalendarSupportMode == ImapCalendarSupportMode.CalDav)
                {
                    SetStepInProgress(Translator.AccountSetup_Step_DiscoveringCalDav);
                    SetCurrentStepSucceeded();

                    SetStepInProgress(Translator.AccountSetup_Step_TestingCalendarAuth);
                    await ValidateCalDavConnectivityAsync(customServerInformation);
                    SetCurrentStepSucceeded();
                }

                // Step: Save to DB
                SetStepInProgress(Translator.AccountSetup_Step_SavingAccount);
                await _accountService.CreateAccountAsync(_createdAccount, customServerInformation);
                _dbWritten = true;
                SetCurrentStepSucceeded();

                // Step: Folders
                SetStepInProgress(Translator.AccountSetup_Step_SyncingFolders);
                var folderResult = await SynchronizationManager.Instance.SynchronizeFoldersAsync(_createdAccount.Id);
                if (folderResult == null || folderResult.CompletedState != SynchronizationCompletedState.Success)
                    throw new Exception(Translator.Exception_FailedToSynchronizeFolders);
                SetCurrentStepSucceeded();

                // Step: Calendar metadata (if not disabled)
                if (_createdAccount.IsCalendarAccessGranted)
                {
                    SetStepInProgress(Translator.AccountSetup_Step_FetchingCalendarMetadata);
                    var calResult = await SynchronizationManager.Instance.SynchronizeCalendarAsync(new CalendarSynchronizationOptions
                    {
                        AccountId = _createdAccount.Id,
                        Type = CalendarSynchronizationType.CalendarMetadata
                    });
                    if (calResult == null || calResult.CompletedState != SynchronizationCompletedState.Success)
                        throw new Exception(Translator.Exception_FailedToSynchronizeCalendarMetadata);
                    SetCurrentStepSucceeded();
                }

                // Aliases for IMAP
                await _accountService.CreateRootAliasAsync(_createdAccount.Id, _createdAccount.Address);
            }
            else // Generic IMAP
            {
                var setupResult = WizardContext.ImapCalDavSetupResult
                    ?? throw new Exception("IMAP setup was not completed.");

                customServerInformation = setupResult.ServerInformation
                    ?? throw new Exception("Server information is missing.");

                customServerInformation.Id = Guid.NewGuid();
                customServerInformation.AccountId = _createdAccount.Id;

                _createdAccount.Address = setupResult.EmailAddress;
                _createdAccount.SenderName = setupResult.DisplayName;
                _createdAccount.IsCalendarAccessGranted = setupResult.IsCalendarAccessGranted;
                _createdAccount.ServerInformation = customServerInformation;

                // Step: Save to DB
                SetStepInProgress(Translator.AccountSetup_Step_SavingAccount);
                await _accountService.CreateAccountAsync(_createdAccount, customServerInformation);
                _dbWritten = true;
                SetCurrentStepSucceeded();

                // Step: Folders
                SetStepInProgress(Translator.AccountSetup_Step_SyncingFolders);
                var folderResult = await SynchronizationManager.Instance.SynchronizeFoldersAsync(_createdAccount.Id);
                if (folderResult == null || folderResult.CompletedState != SynchronizationCompletedState.Success)
                    throw new Exception(Translator.Exception_FailedToSynchronizeFolders);
                SetCurrentStepSucceeded();

                // Step: CalDAV (if applicable)
                if (setupResult.IsCalendarAccessGranted &&
                    customServerInformation.CalendarSupportMode == ImapCalendarSupportMode.CalDav)
                {
                    SetStepInProgress(Translator.AccountSetup_Step_DiscoveringCalDav);
                    SetCurrentStepSucceeded();

                    SetStepInProgress(Translator.AccountSetup_Step_TestingCalendarAuth);
                    await ValidateCalDavConnectivityAsync(customServerInformation);
                    SetCurrentStepSucceeded();
                }

                // Step: Calendar metadata
                if (setupResult.IsCalendarAccessGranted)
                {
                    SetStepInProgress(Translator.AccountSetup_Step_FetchingCalendarMetadata);
                    var calResult = await SynchronizationManager.Instance.SynchronizeCalendarAsync(new CalendarSynchronizationOptions
                    {
                        AccountId = _createdAccount.Id,
                        Type = CalendarSynchronizationType.CalendarMetadata
                    });
                    if (calResult == null || calResult.CompletedState != SynchronizationCompletedState.Success)
                        throw new Exception(Translator.Exception_FailedToSynchronizeCalendarMetadata);
                    SetCurrentStepSucceeded();
                }

                // Aliases for IMAP
                await _accountService.CreateRootAliasAsync(_createdAccount.Id, _createdAccount.Address);
            }

            // Step: Finalizing
            SetStepInProgress(Translator.AccountSetup_Step_Finalizing);
            SetCurrentStepSucceeded();

            IsSetupComplete = true;

            // Notify listeners — this triggers ShellWindow creation from App.xaml.cs
            Messenger.Send(new AccountCreatedMessage(_createdAccount));
        }
        catch (AccountSetupCanceledException)
        {
            // User canceled authentication — go back silently, no error UI
            Messenger.Send(new BackBreadcrumNavigationRequested(NavigationTransitionEffect.FromLeft));
        }
        catch (Exception ex) when (ex.Message.Contains(nameof(AccountSetupCanceledException)))
        {
            // Wrapped cancellation — same silent behavior
            Messenger.Send(new BackBreadcrumNavigationRequested(NavigationTransitionEffect.FromLeft));
        }
        catch (Exception ex)
        {
            Log.Error(ex, "Account setup failed.");

            SetCurrentStepFailed(ex.Message);
            IsSetupFailed = true;
            FailureMessage = Translator.AccountSetup_FailureMessage;

            // Rollback if DB write happened
            if (_dbWritten && _createdAccount != null)
            {
                try
                {
                    await _accountService.DeleteAccountAsync(_createdAccount);
                }
                catch (Exception deleteEx)
                {
                    Log.Error(deleteEx, "Failed to rollback account creation.");
                }

                _dbWritten = false;
            }
        }
    }

    private async Task ValidateImapConnectivityAsync(CustomServerInformation serverInformation)
    {
        var connectivityResult = await SynchronizationManager.Instance
            .TestImapConnectivityAsync(serverInformation, allowSSLHandshake: false);

        if (connectivityResult.IsCertificateUIRequired)
        {
            var certificateMessage =
                $"{Translator.IMAPSetupDialog_CertificateAllowanceRequired_Row0}\n\n" +
                $"{Translator.IMAPSetupDialog_CertificateIssuer}: {connectivityResult.CertificateIssuer}\n" +
                $"{Translator.IMAPSetupDialog_CertificateValidFrom}: {connectivityResult.CertificateValidFromDateString}\n" +
                $"{Translator.IMAPSetupDialog_CertificateValidTo}: {connectivityResult.CertificateExpirationDateString}\n\n" +
                $"{Translator.IMAPSetupDialog_CertificateAllowanceRequired_Row1}";

            var allowCertificate = await _dialogService.ShowConfirmationDialogAsync(
                certificateMessage,
                Translator.GeneralTitle_Warning,
                Translator.Buttons_Allow);

            if (!allowCertificate)
                throw new InvalidOperationException(Translator.IMAPSetupDialog_CertificateDenied);

            connectivityResult = await SynchronizationManager.Instance
                .TestImapConnectivityAsync(serverInformation, allowSSLHandshake: true);
        }

        if (!connectivityResult.IsSuccess)
            throw new InvalidOperationException(connectivityResult.FailedReason ?? Translator.IMAPSetupDialog_ConnectionFailedMessage);
    }

    private async Task ValidateCalDavConnectivityAsync(CustomServerInformation serverInformation)
    {
        if (string.IsNullOrWhiteSpace(serverInformation.CalDavServiceUrl))
            throw new InvalidOperationException(Translator.ImapCalDavSettingsPage_CalDavUrlRequired);

        var settings = new CalDavConnectionSettings
        {
            ServiceUri = new Uri(serverInformation.CalDavServiceUrl, UriKind.Absolute),
            Username = serverInformation.CalDavUsername,
            Password = serverInformation.CalDavPassword
        };

        await _calDavClient.DiscoverCalendarsAsync(settings);
    }

    [RelayCommand]
    private void GoBack()
    {
        Messenger.Send(new BackBreadcrumNavigationRequested(NavigationTransitionEffect.FromLeft));
    }

    [RelayCommand]
    private async Task TryAgainAsync()
    {
        await RunSetupAsync();
    }
}
