using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Jellyfin.Database.Implementations;
using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Extensions;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace Jellyfin.Server.Migrations.Routines;
/// 
/// Migration to re-read creation dates for library items with internal metadata paths.
/// 
[JellyfinMigration("2025-04-20T23:00:00", nameof(RefreshInternalDateModified))]
public class RefreshInternalDateModified : IDatabaseMigrationRoutine
{
    private readonly ILogger _logger;
    private readonly IDbContextFactory _dbProvider;
    private readonly IFileSystem _fileSystem;
    private readonly IServerApplicationHost _applicationHost;
    private readonly bool _useFileCreationTimeForDateAdded;
    private IReadOnlyList _internalTypes = [
         typeof(Genre).FullName!,
         typeof(MusicGenre).FullName!,
         typeof(MusicArtist).FullName!,
         typeof(People).FullName!,
         typeof(Studio).FullName!
    ];
    private IReadOnlyList _internalPaths;
    /// 
    /// Initializes a new instance of the  class.
    /// 
    /// Instance of the  interface.
    /// Instance of the  interface.
    /// Instance of the  interface.
    /// Instance of the  interface.
    /// The logger.
    /// Instance of the  interface.
    public RefreshInternalDateModified(
        IServerApplicationHost applicationHost,
        IServerApplicationPaths applicationPaths,
        IServerConfigurationManager configurationManager,
        IDbContextFactory dbProvider,
        ILogger logger,
        IFileSystem fileSystem)
    {
        _dbProvider = dbProvider;
        _logger = logger;
        _fileSystem = fileSystem;
        _applicationHost = applicationHost;
        _internalPaths = [
            applicationPaths.ArtistsPath,
            applicationPaths.GenrePath,
            applicationPaths.MusicGenrePath,
            applicationPaths.StudioPath,
            applicationPaths.PeoplePath
        ];
        _useFileCreationTimeForDateAdded = configurationManager.GetMetadataConfiguration().UseFileCreationTimeForDateAdded;
    }
    /// 
    public void Perform()
    {
        const int Limit = 5000;
        int itemCount = 0, offset = 0;
        var sw = Stopwatch.StartNew();
        using var context = _dbProvider.CreateDbContext();
        var records = context.BaseItems.Count(b => _internalTypes.Contains(b.Type));
        _logger.LogInformation("Checking if {Count} potentially internal items require refreshed DateModified", records);
        do
        {
            var results = context.BaseItems
                            .Where(b => _internalTypes.Contains(b.Type))
                            .OrderBy(e => e.Id)
                            .Skip(offset)
                            .Take(Limit)
                            .ToList();
            foreach (var item in results)
            {
                var itemPath = item.Path;
                if (itemPath is not null)
                {
                    var realPath = _applicationHost.ExpandVirtualPath(item.Path);
                    if (_internalPaths.Any(path => realPath.StartsWith(path, StringComparison.Ordinal)))
                    {
                        var writeTime = _fileSystem.GetLastWriteTimeUtc(realPath);
                        var itemModificationTime = item.DateModified;
                        if (writeTime != itemModificationTime)
                        {
                            _logger.LogDebug("Reset file modification date: Old: {Old} - New: {New} - Path: {Path}", itemModificationTime, writeTime, realPath);
                            item.DateModified = writeTime;
                            if (_useFileCreationTimeForDateAdded)
                            {
                                item.DateCreated = _fileSystem.GetCreationTimeUtc(realPath);
                            }
                            itemCount++;
                        }
                    }
                }
            }
            offset += Limit;
            if (offset > records)
            {
                offset = records;
            }
            _logger.LogInformation("Checked: {Count} - Refreshed: {Items} - Time: {Time}", offset, itemCount, sw.Elapsed);
        } while (offset < records);
        context.SaveChanges();
        _logger.LogInformation("Refreshed DateModified for {Count} items in {Time}", itemCount, sw.Elapsed);
    }
}