using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Dalamud.Plugin.Services;
using Lumina.Excel.Sheets;
using MareSynchronos.MareConfiguration;
using MareSynchronos.MareConfiguration.Models;
using MareSynchronos.Services;
using MareSynchronos.Services.Mediator;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace MareSynchronos.Services.AutoDetect;

public sealed class AutoDetectSuppressionService : IHostedService, IMediatorSubscriber
{
    private static readonly string[] ContentTypeKeywords =
    [
        "dungeon",
        "donjon",
        "raid",
        "trial",
        "défi",
        "front",
        "frontline",
        "pvp",
        "jcj",
        "conflict",
        "conflit"
    ];

    private readonly ILogger<AutoDetectSuppressionService> _logger;
    private readonly MareConfigService _configService;
    private readonly IClientState _clientState;
    private readonly IDataManager _dataManager;
    private readonly MareMediator _mediator;
    private readonly DalamudUtilService _dalamudUtilService;

    private bool _isSuppressed;
    private bool _hasSavedState;
    private bool _savedDiscoveryEnabled;
    private bool _savedAllowRequests;
    private bool _suppressionWarningShown;
    public bool IsSuppressed => _isSuppressed;

    public AutoDetectSuppressionService(ILogger<AutoDetectSuppressionService> logger,
        MareConfigService configService, IClientState clientState,
        IDataManager dataManager, DalamudUtilService dalamudUtilService, MareMediator mediator)
    {
        _logger = logger;
        _configService = configService;
        _clientState = clientState;
        _dataManager = dataManager;
        _dalamudUtilService = dalamudUtilService;
        _mediator = mediator;
    }

    public MareMediator Mediator => _mediator;

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _mediator.Subscribe<ZoneSwitchEndMessage>(this, _ => UpdateSuppressionState());
        _mediator.Subscribe<DalamudLoginMessage>(this, _ => UpdateSuppressionState());
        _mediator.Subscribe<DalamudLogoutMessage>(this, _ => ClearSuppression());
        UpdateSuppressionState();
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _mediator.UnsubscribeAll(this);
        return Task.CompletedTask;
    }

    private void UpdateSuppressionState()
    {
        _ = _dalamudUtilService.RunOnFrameworkThread(() =>
        {
            try
            {
                if (!_clientState.IsLoggedIn || _clientState.LocalPlayer == null)
                {
                    ClearSuppression();
                    return;
                }

                uint territoryId = _clientState.TerritoryType;
                bool shouldSuppress = ShouldSuppressForTerritory(territoryId);
                ApplySuppression(shouldSuppress, territoryId);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "Failed to update AutoDetect suppression state");
            }
        });
    }

    private void ApplySuppression(bool shouldSuppress, uint territoryId)
    {
        if (shouldSuppress)
        {
            if (!_isSuppressed)
            {
                _savedDiscoveryEnabled = _configService.Current.EnableAutoDetectDiscovery;
                _savedAllowRequests = _configService.Current.AllowAutoDetectPairRequests;
                _hasSavedState = true;
                _isSuppressed = true;
            }

            bool changed = false;
            if (_configService.Current.EnableAutoDetectDiscovery)
            {
                _configService.Current.EnableAutoDetectDiscovery = false;
                changed = true;
            }
            if (_configService.Current.AllowAutoDetectPairRequests)
            {
                _configService.Current.AllowAutoDetectPairRequests = false;
                changed = true;
            }

            if (changed)
            {
                _logger.LogInformation("AutoDetect temporarily disabled in instanced content (territory {territoryId}).", territoryId);
                if (!_suppressionWarningShown)
                {
                    _suppressionWarningShown = true;
                    const string warningText = "Zone instanciée détectée : les fonctions AutoDetect/Nearby sont coupées pour économiser de la bande passante.";
                    _mediator.Publish(new DualNotificationMessage("AutoDetect désactivé",
                        warningText,
                        NotificationType.Warning, TimeSpan.FromSeconds(5)));
                }
            }

            return;
        }
        else
        {
            if (!_isSuppressed) return;

            bool changed = false;
            bool wasSuppressed = _suppressionWarningShown;
            if (_hasSavedState)
            {
                if (_configService.Current.EnableAutoDetectDiscovery != _savedDiscoveryEnabled)
                {
                    _configService.Current.EnableAutoDetectDiscovery = _savedDiscoveryEnabled;
                    changed = true;
                }
                if (_configService.Current.AllowAutoDetectPairRequests != _savedAllowRequests)
                {
                    _configService.Current.AllowAutoDetectPairRequests = _savedAllowRequests;
                    changed = true;
                }
            }

            _isSuppressed = false;
            _hasSavedState = false;
            _suppressionWarningShown = false;

            if (changed || wasSuppressed)
            {
                _logger.LogInformation("AutoDetect restored after leaving instanced content (territory {territoryId}).", territoryId);
                const string restoredText = "Vous avez quitté la zone instanciée : AutoDetect/Nearby fonctionnent de nouveau.";
                _mediator.Publish(new DualNotificationMessage("AutoDetect réactivé",
                    restoredText,
                    NotificationType.Info, TimeSpan.FromSeconds(5)));
            }
        }
    }

    private void ClearSuppression()
    {
        if (!_isSuppressed) return;
        _isSuppressed = false;
        if (_hasSavedState)
        {
            _configService.Current.EnableAutoDetectDiscovery = _savedDiscoveryEnabled;
            _configService.Current.AllowAutoDetectPairRequests = _savedAllowRequests;
        }
        _hasSavedState = false;
        _suppressionWarningShown = false;
    }

    private bool ShouldSuppressForTerritory(uint territoryId)
    {
        if (territoryId == 0) return false;

        var cfcSheet = _dataManager.GetExcelSheet<ContentFinderCondition>();
        if (cfcSheet == null) return false;

        var cfc = cfcSheet.FirstOrDefault(c => c.TerritoryType.RowId == territoryId);
        if (cfc.RowId == 0) return false;

        if (MatchesSuppressionKeyword(cfc.Name.ToString())) return true;

        var contentType = cfc.ContentType.Value;
        if (contentType.RowId == 0) return false;

        return MatchesSuppressionKeyword(contentType.Name.ToString());
    }

    private static bool MatchesSuppressionKeyword(string? text)
    {
        if (string.IsNullOrWhiteSpace(text)) return false;
        return ContentTypeKeywords.Any(keyword => text.Contains(keyword, StringComparison.OrdinalIgnoreCase));
    }
}
