using System.Collections.ObjectModel;
using System.Windows;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Extensions.Logging;
using Serilog;
using SharepointToolbox.Core.Models;
using SharepointToolbox.Infrastructure.Persistence;
using SharepointToolbox.Localization;
using SharepointToolbox.Services;

namespace SharepointToolbox.ViewModels.Tabs;

public partial class TemplatesViewModel : FeatureViewModelBase
{
    private readonly ITemplateService _templateService;
    private readonly TemplateRepository _templateRepo;
    private readonly ISessionManager _sessionManager;
    private readonly ILogger<FeatureViewModelBase> _logger;
    private TenantProfile? _currentProfile;

    // Template list
    private ObservableCollection<SiteTemplate> _templates = new();
    public ObservableCollection<SiteTemplate> Templates
    {
        get => _templates;
        private set { _templates = value; OnPropertyChanged(); }
    }

    [ObservableProperty] private SiteTemplate? _selectedTemplate;

    // Capture options
    [ObservableProperty] private string _templateName = string.Empty;
    [ObservableProperty] private bool _captureLibraries = true;
    [ObservableProperty] private bool _captureFolders = true;
    [ObservableProperty] private bool _capturePermissions = true;
    [ObservableProperty] private bool _captureLogo = true;
    [ObservableProperty] private bool _captureSettings = true;

    // Apply options
    [ObservableProperty] private string _newSiteTitle = string.Empty;
    [ObservableProperty] private string _newSiteAlias = string.Empty;
    private bool _aliasManuallyEdited;

    public IAsyncRelayCommand CaptureCommand { get; }
    public IAsyncRelayCommand ApplyCommand { get; }
    public IAsyncRelayCommand RenameCommand { get; }
    public IAsyncRelayCommand DeleteCommand { get; }
    public IAsyncRelayCommand RefreshCommand { get; }

    public TenantProfile? CurrentProfile => _currentProfile;

    // Factory for rename dialog — set by View code-behind
    public Func<string, string?>? RenameDialogFactory { get; set; }

    public TemplatesViewModel(
        ITemplateService templateService,
        TemplateRepository templateRepo,
        ISessionManager sessionManager,
        ILogger<FeatureViewModelBase> logger)
        : base(logger)
    {
        _templateService = templateService;
        _templateRepo = templateRepo;
        _sessionManager = sessionManager;
        _logger = logger;

        CaptureCommand = new AsyncRelayCommand(CaptureAsync, () => !IsRunning);
        ApplyCommand = new AsyncRelayCommand(ApplyAsync, () => !IsRunning && SelectedTemplate != null);
        RenameCommand = new AsyncRelayCommand(RenameAsync, () => SelectedTemplate != null);
        DeleteCommand = new AsyncRelayCommand(DeleteAsync, () => SelectedTemplate != null);
        RefreshCommand = new AsyncRelayCommand(RefreshListAsync);
    }

    protected override async Task RunOperationAsync(CancellationToken ct, IProgress<OperationProgress> progress)
    {
        // Not used directly — Capture and Apply have their own async commands
        await Task.CompletedTask;
    }

    private async Task CaptureAsync()
    {
        var T = TranslationSource.Instance;
        if (_currentProfile == null)
            throw new InvalidOperationException(T["err.no_tenant"]);
        if (string.IsNullOrWhiteSpace(TemplateName))
            throw new InvalidOperationException(T["err.template_name_required"]);

        var captureSiteUrl = GlobalSites.Select(s => s.Url).FirstOrDefault(u => !string.IsNullOrWhiteSpace(u));
        if (string.IsNullOrWhiteSpace(captureSiteUrl))
            throw new InvalidOperationException(T["err.no_sites_selected"]);

        try
        {
            IsRunning = true;
            StatusMessage = T["templates.status.capturing"];

            var profile = new TenantProfile
            {
                Name = _currentProfile.Name,
                TenantUrl = captureSiteUrl,
                ClientId = _currentProfile.ClientId,
            };
            var ctx = await _sessionManager.GetOrCreateContextAsync(profile, CancellationToken.None);

            var options = new SiteTemplateOptions
            {
                CaptureLibraries = CaptureLibraries,
                CaptureFolders = CaptureFolders,
                CapturePermissionGroups = CapturePermissions,
                CaptureLogo = CaptureLogo,
                CaptureSettings = CaptureSettings,
            };

            var progress = new Progress<OperationProgress>(p => StatusMessage = p.Message);
            var template = await _templateService.CaptureTemplateAsync(ctx, options, progress, CancellationToken.None);
            template.Name = TemplateName;

            await _templateRepo.SaveAsync(template);
            Log.Information("Template captured: {Name} from {Url}", template.Name, captureSiteUrl);

            await RefreshListAsync();
            StatusMessage = T["templates.status.success"];
        }
        catch (Exception ex)
        {
            StatusMessage = string.Format(T["templates.status.capture_failed"], ex.Message);
            Log.Error(ex, "Template capture failed");
        }
        finally
        {
            IsRunning = false;
        }
    }

    private async Task ApplyAsync()
    {
        if (_currentProfile == null || SelectedTemplate == null) return;
        var T = TranslationSource.Instance;
        if (string.IsNullOrWhiteSpace(NewSiteTitle))
            throw new InvalidOperationException(T["err.site_title_required"]);

        // Auto-fill alias from title if user left it blank
        if (string.IsNullOrWhiteSpace(NewSiteAlias))
        {
            var generated = GenerateAliasFromTitle(NewSiteTitle);
            if (string.IsNullOrWhiteSpace(generated))
                throw new InvalidOperationException(T["err.site_alias_required"]);
            NewSiteAlias = generated;
        }

        try
        {
            IsRunning = true;
            StatusMessage = T["templates.status.applying"];

            var ctx = await _sessionManager.GetOrCreateContextAsync(_currentProfile, CancellationToken.None);
            var progress = new Progress<OperationProgress>(p => StatusMessage = p.Message);

            var siteUrl = await _templateService.ApplyTemplateAsync(
                ctx, SelectedTemplate, NewSiteTitle, NewSiteAlias,
                progress, CancellationToken.None);

            StatusMessage = string.Format(T["templates.status.applied"], siteUrl);
            Log.Information("Template applied. New site: {Url}", siteUrl);
        }
        catch (Exception ex)
        {
            StatusMessage = string.Format(T["templates.status.apply_failed"], ex.Message);
            Log.Error(ex, "Template apply failed");
        }
        finally
        {
            IsRunning = false;
        }
    }

    private async Task RenameAsync()
    {
        if (SelectedTemplate == null) return;

        if (RenameDialogFactory != null)
        {
            var newName = RenameDialogFactory(SelectedTemplate.Name);
            if (!string.IsNullOrWhiteSpace(newName))
            {
                await _templateRepo.RenameAsync(SelectedTemplate.Id, newName);
                await RefreshListAsync();
                Log.Information("Template renamed.");
            }
        }
    }

    private async Task DeleteAsync()
    {
        if (SelectedTemplate == null) return;

        await _templateRepo.DeleteAsync(SelectedTemplate.Id);
        await RefreshListAsync();
        Log.Information("Template deleted.");
    }

    private async Task RefreshListAsync()
    {
        var templates = await _templateRepo.GetAllAsync();
        await Application.Current.Dispatcher.InvokeAsync(() =>
        {
            Templates = new ObservableCollection<SiteTemplate>(templates);
        });
    }

    protected override void OnTenantSwitched(TenantProfile profile)
    {
        _currentProfile = profile;
        TemplateName = string.Empty;
        NewSiteTitle = string.Empty;
        NewSiteAlias = string.Empty;
        _aliasManuallyEdited = false;
        StatusMessage = string.Empty;

        _ = RefreshListAsync();
    }

    partial void OnSelectedTemplateChanged(SiteTemplate? value)
    {
        ApplyCommand.NotifyCanExecuteChanged();
        RenameCommand.NotifyCanExecuteChanged();
        DeleteCommand.NotifyCanExecuteChanged();
    }

    partial void OnNewSiteTitleChanged(string value)
    {
        if (_aliasManuallyEdited) return;
        var generated = GenerateAliasFromTitle(value);
        if (NewSiteAlias != generated)
        {
            // Bypass user-edit flag while we sync alias to title
            _suppressAliasEditedFlag = true;
            NewSiteAlias = generated;
            _suppressAliasEditedFlag = false;
        }
    }

    private bool _suppressAliasEditedFlag;

    partial void OnNewSiteAliasChanged(string value)
    {
        if (_suppressAliasEditedFlag) return;
        _aliasManuallyEdited = !string.IsNullOrWhiteSpace(value)
            && value != GenerateAliasFromTitle(NewSiteTitle);
        if (string.IsNullOrWhiteSpace(value)) _aliasManuallyEdited = false;
    }

    internal static string GenerateAliasFromTitle(string title)
    {
        if (string.IsNullOrWhiteSpace(title)) return string.Empty;

        var normalized = title.Normalize(System.Text.NormalizationForm.FormD);
        var sb = new System.Text.StringBuilder(normalized.Length);
        foreach (var c in normalized)
        {
            var cat = System.Globalization.CharUnicodeInfo.GetUnicodeCategory(c);
            if (cat == System.Globalization.UnicodeCategory.NonSpacingMark) continue;
            if (char.IsLetterOrDigit(c)) sb.Append(c);
            else if (c == ' ' || c == '-' || c == '_') sb.Append('-');
        }
        var collapsed = System.Text.RegularExpressions.Regex.Replace(sb.ToString(), "-+", "-");
        return collapsed.Trim('-');
    }
}
