using KiMailOrderAgent.Agents;
using KiMailOrderAgent.Approval;
using KiMailOrderAgent.Attachments;
using KiMailOrderAgent.Mail;
using KiMailOrderAgent.Models;
using KiMailOrderAgent.Services;
using KiMailOrderAgent.Storage;
using KiMailOrderAgent.Wawi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Text;

namespace KiMailOrderAgent;

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;
    private readonly IMailReader _mailReader;
    private readonly OrderAgent _orderAgent;
    private readonly ApprovalMessageBuilder _messageBuilder;
    private readonly IApprovalNotifier _approvalNotifier;
    private readonly IWawiOrderService _wawiOrderService;
    private readonly OrderValidator _orderValidator;
    private readonly IAttachmentTextExtractor _attachmentTextExtractor;
    private readonly CorrectionAgent _correctionAgent;
    private readonly MailPreFilter _mailPreFilter;
    private readonly IServiceProvider _serviceProvider;

    private bool _testMailAlreadySent = false;

    public Worker(
        ILogger<Worker> logger,
        IMailReader mailReader,
        OrderAgent orderAgent,
        ApprovalMessageBuilder messageBuilder,
        IApprovalNotifier approvalNotifier,
        IWawiOrderService wawiOrderService,
        OrderValidator orderValidator,
        IAttachmentTextExtractor attachmentTextExtractor, 
        CorrectionAgent correctionAgent, MailPreFilter mailPreFilter, 
        IServiceProvider serviceProvider)
    {
        _logger = logger;
        _mailReader = mailReader;
        _orderAgent = orderAgent;
        _messageBuilder = messageBuilder;
        _approvalNotifier = approvalNotifier;
        _wawiOrderService = wawiOrderService;
        _orderValidator = orderValidator;
        _attachmentTextExtractor = attachmentTextExtractor;
        _correctionAgent = correctionAgent;
        _mailPreFilter = mailPreFilter;
        _serviceProvider = serviceProvider;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("KiMailOrderAgent gestartet");

        using var scope = _serviceProvider.CreateScope();

        var db =
            scope.ServiceProvider
                .GetRequiredService<WawiDbService>();

        await db.SyncArticlesAsync();

        _logger.LogInformation("Artikel Sync fertig, starte Mailprüfung.");

        try
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                var mails = await _mailReader.GetUnreadMailsAsync(stoppingToken);

                foreach (var mail in mails)
                {
                    if (mail.Subject.StartsWith("Re:", StringComparison.OrdinalIgnoreCase))
                    {
                        await ProcessApprovalResponseAsync(mail, stoppingToken);
                    }
                    else
                    {
                        await ProcessIncomingOrderMailAsync(mail, stoppingToken);
                    }
                }

                await Task.Delay(TimeSpan.FromSeconds(15), stoppingToken);
            }
        }
        catch (OperationCanceledException)
        {
            // normal beim Beenden
        }

        _logger.LogInformation("KiMailOrderAgent gestoppt");
    }

    private async Task ProcessIncomingOrderMailAsync(IncomingMail mail, CancellationToken stoppingToken)
    {
        _logger.LogInformation("Neue Mail erhalten von: {from}", mail.From);
        _logger.LogInformation("Betreff: {subject}", mail.Subject);

        if (!_mailPreFilter.IsAllowedSender(mail))
        {
            _logger.LogInformation("Absender nicht freigegeben, Mail wird ignoriert: {from}", mail.From);
            return;
        }

        var processedStore = new ProcessedMailStore();

        if (processedStore.IsProcessed(mail.Id))
        {
            _logger.LogInformation("Mail {id} wurde bereits verarbeitet. Überspringe.", mail.Id);
            return;
        }

        var fullTextBuilder = new StringBuilder();

        fullTextBuilder.AppendLine("MAILTEXT:");
        fullTextBuilder.AppendLine(mail.Body);

        foreach (var attachment in mail.Attachments)
        {
            var attachmentText = await _attachmentTextExtractor.ExtractTextAsync(
                attachment,
                stoppingToken);

            if (!string.IsNullOrWhiteSpace(attachmentText))
            {
                fullTextBuilder.AppendLine();
                fullTextBuilder.AppendLine($"ANHANG: {attachment.FileName}");
                fullTextBuilder.AppendLine(attachmentText);
            }
        }

        var fullOrderText = fullTextBuilder.ToString();

        var order = await _orderAgent.ExtractOrderAsync(fullOrderText);

        if (order == null)
        {
            _logger.LogWarning("❌ KI konnte keine Bestellung erkennen.");
            return;
        }

        order.OriginalMailFrom = mail.From;
        order.OriginalMailSubject = mail.Subject;

        var validation = _orderValidator.Validate(order);

        foreach (var error in validation.Errors)
            _logger.LogWarning("❌ Validierungsfehler: {error}", error);

        foreach (var warning in validation.Warnings)
            _logger.LogWarning("⚠️ Warnung: {warning}", warning);

        var store = new PendingOrderStore();
        var orders = store.Load();

        orders.Add(order);
        store.Save(orders);

        _logger.LogInformation("Bestellung gespeichert mit ID: {id}", order.Id);

        var message = _messageBuilder.Build(order);

        await _approvalNotifier.SendApprovalRequestAsync(
            order,
            message,
            stoppingToken);

        _logger.LogInformation("Freigabe-Mail wurde gesendet.");
        processedStore.MarkAsProcessed(mail.Id);
    }

    private async Task ProcessApprovalResponseAsync(IncomingMail responseMail, CancellationToken stoppingToken)
    {
        _logger.LogInformation("Antwort-Mail erhalten: {subject}", responseMail.Subject);

        var orderId = ExtractOrderIdFromSubject(responseMail.Subject);

        if (string.IsNullOrWhiteSpace(orderId))
        {
            _logger.LogWarning("Keine Bestell-ID im Betreff gefunden.");
            return;
        }

        var store = new PendingOrderStore();
        var order = store.FindById(orderId);

        if (order == null)
        {
            _logger.LogWarning("Keine gespeicherte Bestellung mit ID {id} gefunden.", orderId);
            return;
        }

        var body = responseMail.Body
            .Replace("\r", "")
            .Trim();

        var firstLine = body
            .Split('\n', StringSplitOptions.RemoveEmptyEntries)
            .FirstOrDefault()?
            .Trim();

        if (firstLine != null &&
            firstLine.StartsWith("OK", StringComparison.OrdinalIgnoreCase))
        {
            order.ApprovalStatus = ApprovalStatus.Approved;
            order.ProcessingStatus = ProcessingStatus.Approved;

            store.Update(order);

            _logger.LogInformation("✅ Bestellung {id} wurde freigegeben.", order.Id);

            await _wawiOrderService.CreateOrderAsync(order, stoppingToken);

            order.ProcessingStatus = ProcessingStatus.CreatedInWawi;
            store.Update(order);

            _logger.LogInformation("✅ Bestellung {id} wurde als CreatedInWawi gespeichert.", order.Id);
        }
        else if (firstLine != null &&
                 firstLine.StartsWith("ABLEHNEN", StringComparison.OrdinalIgnoreCase))
        {
            order.ApprovalStatus = ApprovalStatus.Rejected;
            order.ProcessingStatus = ProcessingStatus.Failed;

            store.Update(order);

            _logger.LogInformation("❌ Bestellung {id} wurde abgelehnt.", order.Id);
        }
        else if (firstLine != null &&
         firstLine.StartsWith("KORREKTUR:", StringComparison.OrdinalIgnoreCase))
        {
            var correctionText = responseMail.Body;

            _logger.LogInformation("⚠️ Korrektur für Bestellung {id}: {text}", order.Id, correctionText);

            var correctedOrder = await _correctionAgent.ApplyCorrectionAsync(
                order,
                correctionText,
                stoppingToken);

            if (correctedOrder == null)
            {
                _logger.LogWarning("❌ Korrektur konnte nicht angewendet werden.");
                return;
            }

            correctedOrder.Id = order.Id;
            correctedOrder.OriginalMailFrom = order.OriginalMailFrom;
            correctedOrder.OriginalMailSubject = order.OriginalMailSubject;
            correctedOrder.ApprovalStatus = ApprovalStatus.Pending;
            correctedOrder.ProcessingStatus = ProcessingStatus.PendingApproval;

            store.Update(correctedOrder);

            var message = _messageBuilder.Build(correctedOrder);

            await _approvalNotifier.SendApprovalRequestAsync(
                correctedOrder,
                message,
                stoppingToken);

            _logger.LogInformation("Neue Freigabe-Mail nach Korrektur wurde gesendet.");
        }
        else
        {
            order.ApprovalStatus = ApprovalStatus.NeedsCorrection;
            store.Update(order);

            _logger.LogInformation("⚠️ Unklare Antwort für Bestellung {id}: {text}", order.Id, firstLine);
        }
    }

    private static string? ExtractOrderIdFromSubject(string subject)
    {
        var start = subject.IndexOf('[');
        var end = subject.IndexOf(']');

        if (start < 0 || end < 0 || end <= start)
            return null;

        return subject.Substring(start + 1, end - start - 1);
    }
}