using IWS5.Importer.Abstractions.FileSystem;
using IWS5.DatabaseAccess.Interfaces.Importer;
using IWS5.Importer.Abstractions.Interfaces;
using IWS5.Importer.Worker.Validation;
using Serilog.Context;
using System.Data;

namespace IWS5.Importer.Worker.Conversion;

public class FileConverterService : IFileConverterService
{
    private readonly IEnumerable<IFileConverter> _converters;
    private readonly IFileMover _fileMover;
    private readonly Serilog.ILogger _logService;
    private readonly HashSet<string> _supportedExtensions;
    private readonly IProcessImportRuleRepository _ruleRepository;

    public FileConverterService(
        IEnumerable<IFileConverter> converters,
        IFileMover fileMover,
        IGeneralImportSettingsProvider settingsProvider,
        Serilog.ILogger logService,
        IProcessImportRuleRepository ruleRepository)
    {
        _converters = converters;
        _fileMover = fileMover;
        _logService = logService;
        _ruleRepository = ruleRepository;

        var allowed = settingsProvider.Settings.AllowedExtensions ?? new();
        SupportedExtensionValidator.ValidateConfigExtensions(allowed);
        _supportedExtensions = allowed.Select(e => e.Trim().ToLowerInvariant()).ToHashSet();
    }

    public async Task<bool> ShouldConvertAsync(string extension, int processId)
    {
        if (string.IsNullOrWhiteSpace(extension))
            return false;

        var normalizedExt = extension.TrimStart('.').ToLowerInvariant();

        // 1. Check if supported at all
        if (!_supportedExtensions.Contains(normalizedExt))
            return false;

        var rule = await _ruleRepository.GetProcessImportRuleAsync(processId);
        var doNotConvert = rule?.DoNotConvert ?? new();

        // 2. Check if explicitly excluded from conversion
        if (doNotConvert.Contains(normalizedExt))
            return false;

        // 3. Check if there is a converter for it
        return _converters.Any(c => c.CanConvert(normalizedExt));
    }


    public async Task<bool> TryConvertToPdfAsync(string inputPath, string outputPath, int processId, CancellationToken cancellationToken)
    {
        string extension = Path.GetExtension(inputPath).TrimStart('.').ToLowerInvariant();

        // 1. Check if the extension is supported and not excluded
        var shouldConvert = await ShouldConvertAsync(extension, processId);
        if (!shouldConvert)
        {
            _logService.Warning("Conversion skipped for {File} due to unsupported or excluded extension.", inputPath);
            _fileMover.MoveFilesToError(new List<string> { inputPath });
            return false;
        }

        // 2. Find a valid converter
        var converter = _converters.FirstOrDefault(c => c.CanConvert(extension));
        if (converter == null)
        {
            _logService.Warning("No converter found for extension: {Ext}.", extension);
            _fileMover.MoveFilesToError(new List<string> { inputPath });
            return false;
        }

        // 3. Convert
        try
        {
            await converter.ConvertAsync(inputPath, outputPath, cancellationToken);
            _logService.Information("Successfully converted: {File}", inputPath);
            return true;
        }
        catch (Exception ex)
        {
            using (LogContext.PushProperty("LogContext", nameof(TryConvertToPdfAsync)))
                _logService.Error(ex, "Error during conversion of file: {File}", inputPath);
            _fileMover.MoveFilesToError(new List<string> { inputPath });
            return false;
        }
    }
}
