using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Extensions.Logging;
using Microsoft.Win32;
using SharepointToolbox.Core.Models;
using SharepointToolbox.Localization;
using SharepointToolbox.Services;
using SharepointToolbox.Services.Export;

namespace SharepointToolbox.ViewModels.Tabs;

/// <summary>Flat display row wrapping a DuplicateItem with its group name.</summary>
public class DuplicateRow
{
    public string GroupName { get; set; } = string.Empty;
    public string Name { get; set; } = string.Empty;
    public string Path { get; set; } = string.Empty;
    public string Library { get; set; } = string.Empty;
    public long? SizeBytes { get; set; }
    public DateTime? Created { get; set; }
    public DateTime? Modified { get; set; }
    public int? FolderCount { get; set; }
    public int? FileCount { get; set; }
    public int GroupSize { get; set; }
}

public partial class DuplicatesViewModel : FeatureViewModelBase
{
    private readonly IDuplicatesService _duplicatesService;
    private readonly ISessionManager _sessionManager;
    private readonly DuplicatesHtmlExportService _htmlExportService;
    private readonly DuplicatesCsvExportService _csvExportService;
    private readonly IBrandingService _brandingService;
    private readonly ILogger<FeatureViewModelBase> _logger;
    private TenantProfile? _currentProfile;
    private IReadOnlyList<DuplicateGroup> _lastGroups = Array.Empty<DuplicateGroup>();

    [ObservableProperty] private bool _modeFiles = true;
    [ObservableProperty] private bool _modeFolders;
    [ObservableProperty] private bool _matchSize = true;
    [ObservableProperty] private bool _matchCreated;
    [ObservableProperty] private bool _matchModified;
    [ObservableProperty] private bool _matchSubfolders;
    [ObservableProperty] private bool _matchFileCount;
    [ObservableProperty] private bool _includeSubsites;
    [ObservableProperty] private string _library = string.Empty;

    /// <summary>0 = Single file, 1 = Split by site.</summary>
    [ObservableProperty] private int _splitModeIndex;
    /// <summary>0 = Separate HTML files, 1 = Single tabbed HTML.</summary>
    [ObservableProperty] private int _htmlLayoutIndex;

    private ReportSplitMode CurrentSplit => SplitModeIndex == 1 ? ReportSplitMode.BySite : ReportSplitMode.Single;
    private HtmlSplitLayout CurrentLayout => HtmlLayoutIndex == 1 ? HtmlSplitLayout.SingleTabbed : HtmlSplitLayout.SeparateFiles;

    private ObservableCollection<DuplicateRow> _results = new();
    public ObservableCollection<DuplicateRow> Results
    {
        get => _results;
        private set
        {
            _results = value;
            OnPropertyChanged();
            ExportHtmlCommand.NotifyCanExecuteChanged();
            ExportCsvCommand.NotifyCanExecuteChanged();
        }
    }

    public IAsyncRelayCommand ExportHtmlCommand { get; }
    public IAsyncRelayCommand ExportCsvCommand { get; }
    public TenantProfile? CurrentProfile => _currentProfile;

    public DuplicatesViewModel(
        IDuplicatesService duplicatesService,
        ISessionManager sessionManager,
        DuplicatesHtmlExportService htmlExportService,
        DuplicatesCsvExportService csvExportService,
        IBrandingService brandingService,
        ILogger<FeatureViewModelBase> logger)
        : base(logger)
    {
        _duplicatesService = duplicatesService;
        _sessionManager    = sessionManager;
        _htmlExportService = htmlExportService;
        _csvExportService  = csvExportService;
        _brandingService   = brandingService;
        _logger            = logger;

        ExportHtmlCommand = new AsyncRelayCommand(ExportHtmlAsync, CanExport);
        ExportCsvCommand  = new AsyncRelayCommand(ExportCsvAsync,  CanExport);
    }

    protected override async Task RunOperationAsync(CancellationToken ct, IProgress<OperationProgress> progress)
    {
        if (_currentProfile == null)
        {
            StatusMessage = TranslationSource.Instance["err.no_tenant_connected"];
            return;
        }

        var urls = GlobalSites.Select(s => s.Url).Where(u => !string.IsNullOrWhiteSpace(u)).ToList();
        if (urls.Count == 0)
        {
            StatusMessage = TranslationSource.Instance["err.no_sites_selected"];
            return;
        }

        var allGroups = new List<DuplicateGroup>();

        foreach (var url in urls)
        {
            var siteProfile = new TenantProfile
            {
                TenantUrl = url.TrimEnd('/'),
                ClientId  = _currentProfile.ClientId,
                Name      = _currentProfile.Name
            };
            var ctx = await _sessionManager.GetOrCreateContextAsync(siteProfile, ct);

            var opts = new DuplicateScanOptions(
                Mode:               ModeFiles ? "Files" : "Folders",
                MatchSize:          MatchSize,
                MatchCreated:       MatchCreated,
                MatchModified:      MatchModified,
                MatchSubfolderCount: MatchSubfolders,
                MatchFileCount:     MatchFileCount,
                IncludeSubsites:    IncludeSubsites,
                Library:            string.IsNullOrWhiteSpace(Library) ? null : Library
            );

            var groups = await _duplicatesService.ScanDuplicatesAsync(ctx, opts, progress, ct);
            allGroups.AddRange(groups);
        }

        _lastGroups = allGroups;

        // Flatten groups to display rows
        var rows = allGroups
            .SelectMany(g => g.Items.Select(item => new DuplicateRow
            {
                GroupName   = g.Name,
                Name        = item.Name,
                Path        = item.Path,
                Library     = item.Library,
                SizeBytes   = item.SizeBytes,
                Created     = item.Created,
                Modified    = item.Modified,
                FolderCount = item.FolderCount,
                FileCount   = item.FileCount,
                GroupSize   = g.Items.Count
            }))
            .ToList();

        if (Application.Current?.Dispatcher is { } dispatcher)
            await dispatcher.InvokeAsync(() => Results = new ObservableCollection<DuplicateRow>(rows));
        else
            Results = new ObservableCollection<DuplicateRow>(rows);
    }

    protected override void OnTenantSwitched(Core.Models.TenantProfile profile)
    {
        _currentProfile = profile;
        Results = new ObservableCollection<DuplicateRow>();
        _lastGroups = Array.Empty<DuplicateGroup>();
        OnPropertyChanged(nameof(CurrentProfile));
        ExportHtmlCommand.NotifyCanExecuteChanged();
        ExportCsvCommand.NotifyCanExecuteChanged();
    }

    internal void SetCurrentProfile(TenantProfile profile) => _currentProfile = profile;

    private bool CanExport() => _lastGroups.Count > 0;

    private async Task ExportHtmlAsync()
    {
        if (_lastGroups.Count == 0) return;
        var dialog = new SaveFileDialog
        {
            Title = "Export duplicates report to HTML",
            Filter = "HTML files (*.html)|*.html|All files (*.*)|*.*",
            DefaultExt = "html",
            FileName = "duplicates_report"
        };
        if (dialog.ShowDialog() != true) return;
        try
        {
            ReportBranding? branding = null;
            if (_brandingService is not null)
            {
                var mspLogo = await _brandingService.GetMspLogoAsync();
                var clientLogo = _currentProfile?.ClientLogo;
                branding = new ReportBranding(mspLogo, clientLogo);
            }

            await _htmlExportService.WriteAsync(_lastGroups, dialog.FileName, CurrentSplit, CurrentLayout, CancellationToken.None, branding);
            Process.Start(new ProcessStartInfo(dialog.FileName) { UseShellExecute = true });
        }
        catch (Exception ex) { StatusMessage = $"Export failed: {ex.Message}"; _logger.LogError(ex, "HTML export failed."); }
    }

    private async Task ExportCsvAsync()
    {
        if (_lastGroups.Count == 0) return;
        var dialog = new SaveFileDialog
        {
            Title = "Export duplicates report to CSV",
            Filter = "CSV files (*.csv)|*.csv|All files (*.*)|*.*",
            DefaultExt = "csv",
            FileName = "duplicates_report"
        };
        if (dialog.ShowDialog() != true) return;
        try
        {
            await _csvExportService.WriteAsync(_lastGroups, dialog.FileName, CurrentSplit, CancellationToken.None);
            Process.Start(new ProcessStartInfo(dialog.FileName) { UseShellExecute = true });
        }
        catch (Exception ex) { StatusMessage = $"Export failed: {ex.Message}"; _logger.LogError(ex, "CSV export failed."); }
    }
}
