using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using LightlessSync.API.Data.Extensions;
using LightlessSync.API.Dto.Group;
using LightlessSync.LightlessConfiguration;
using LightlessSync.PlayerData.Factories;
using LightlessSync.PlayerData.Pairs;
using LightlessSync.PlayerData.Pairs;
using LightlessSync.Services;
using LightlessSync.Services.Mediator;
using LightlessSync.Services.ServerConfiguration;
using LightlessSync.UI.Components;
using LightlessSync.UI.Handlers;
using LightlessSync.UI.Models;
using LightlessSync.WebAPI;
using Microsoft.Extensions.Logging;

namespace LightlessSync.UI;

public class DrawEntityFactory
{
    private readonly ILogger<DrawEntityFactory> _logger;
    private readonly ApiController _apiController;
    private readonly LightlessMediator _mediator;
    private readonly SelectPairForTagUi _selectPairForTagUi;
    private readonly ServerConfigurationManager _serverConfigurationManager;
    private readonly LightlessConfigService _configService;
    private readonly UiSharedService _uiSharedService;
    private readonly PlayerPerformanceConfigService _playerPerformanceConfigService;
    private readonly LocationShareService _locationShareService;
    private readonly CharaDataManager _charaDataManager;
    private readonly SelectTagForPairUi _selectTagForPairUi;
    private readonly RenamePairTagUi _renamePairTagUi;
    private readonly SelectTagForSyncshellUi _selectTagForSyncshellUi;
    private readonly RenameSyncshellTagUi _renameSyncshellTagUi;
    private readonly SelectSyncshellForTagUi _selectSyncshellForTagUi;
    private readonly TagHandler _tagHandler;
    private readonly IdDisplayHandler _uidDisplayHandler;
    private readonly PairLedger _pairLedger;
    private readonly PairFactory _pairFactory;

    public DrawEntityFactory(
        ILogger<DrawEntityFactory> logger,
        ApiController apiController,
        IdDisplayHandler uidDisplayHandler,
        SelectTagForPairUi selectTagForPairUi,
        RenamePairTagUi renamePairTagUi,
        LightlessMediator mediator,
        TagHandler tagHandler,
        SelectPairForTagUi selectPairForTagUi,
        ServerConfigurationManager serverConfigurationManager,
        LightlessConfigService configService,
        UiSharedService uiSharedService,
        PlayerPerformanceConfigService playerPerformanceConfigService,
        LocationShareService locationShareService,
        CharaDataManager charaDataManager,
        SelectTagForSyncshellUi selectTagForSyncshellUi,
        RenameSyncshellTagUi renameSyncshellTagUi,
        SelectSyncshellForTagUi selectSyncshellForTagUi,
        PairLedger pairLedger,
        PairFactory pairFactory)
    {
        _logger = logger;
        _apiController = apiController;
        _uidDisplayHandler = uidDisplayHandler;
        _selectTagForPairUi = selectTagForPairUi;
        _renamePairTagUi = renamePairTagUi;
        _mediator = mediator;
        _tagHandler = tagHandler;
        _selectPairForTagUi = selectPairForTagUi;
        _serverConfigurationManager = serverConfigurationManager;
        _configService = configService;
        _uiSharedService = uiSharedService;
        _playerPerformanceConfigService = playerPerformanceConfigService;
        _locationShareService = locationShareService;
        _charaDataManager = charaDataManager;
        _selectTagForSyncshellUi = selectTagForSyncshellUi;
        _renameSyncshellTagUi = renameSyncshellTagUi;
        _selectSyncshellForTagUi = selectSyncshellForTagUi;
        _pairLedger = pairLedger;
        _pairFactory = pairFactory;
    }

    public DrawFolderGroup CreateGroupFolder(
        string id,
        GroupFullInfoDto groupFullInfo,
        IEnumerable<PairUiEntry> drawEntries,
        IEnumerable<PairUiEntry> allEntries)
    {
        var drawPairs = drawEntries
            .Select(entry => CreateDrawPair($"{id}:{entry.DisplayEntry.Ident.UserId}", entry, groupFullInfo))
            .Where(draw => draw is not null)
            .Cast<DrawUserPair>()
            .ToImmutableList();

        var allPairs = allEntries.ToImmutableList();

        return new DrawFolderGroup(
            id,
            groupFullInfo,
            _apiController,
            drawPairs,
            allPairs,
            _tagHandler,
            _uidDisplayHandler,
            _mediator,
            _uiSharedService,
            _selectTagForSyncshellUi);
    }

    public DrawFolderTag CreateTagFolder(
        string tag,
        IEnumerable<PairUiEntry> drawEntries,
        IEnumerable<PairUiEntry> allEntries)
    {
        var drawPairs = drawEntries
            .Select(entry => CreateDrawPair($"{tag}:{entry.DisplayEntry.Ident.UserId}", entry))
            .Where(draw => draw is not null)
            .Cast<DrawUserPair>()
            .ToImmutableList();

        var allPairs = allEntries.ToImmutableList();

        return new DrawFolderTag(
            tag,
            drawPairs,
            allPairs,
            _tagHandler,
            _apiController,
            _selectPairForTagUi,
            _renamePairTagUi,
            _uiSharedService,
            _serverConfigurationManager,
            _configService,
            _mediator);
    }

    public DrawUserPair? CreateDrawPair(
        string id,
        PairUiEntry entry,
        GroupFullInfoDto? currentGroup = null)
    {
        var pair = _pairFactory.Create(entry.DisplayEntry);
        if (pair is null)
        {
            if (_logger.IsEnabled(LogLevel.Debug))
            {
                _logger.LogDebug("Skipping draw pair for {UserId}: legacy pair not found.", entry.DisplayEntry.Ident.UserId);
            }
            return null;
        }

        return new DrawUserPair(
            id,
            entry,
            pair,
            currentGroup,
            _apiController,
            _uidDisplayHandler,
            _mediator,
            _selectTagForPairUi,
            _serverConfigurationManager,
            _uiSharedService,
            _playerPerformanceConfigService,
            _configService,
            _locationShareService,
            _charaDataManager,
            _pairLedger);
    }

    public IReadOnlyList<PairUiEntry> GetAllEntries()
    {
        try
        {
            return _pairLedger.GetAllEntries()
                .Select(BuildUiEntry)
                .ToList();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to build pair display entries.");
            return Array.Empty<PairUiEntry>();
        }
    }

    private PairUiEntry BuildUiEntry(PairDisplayEntry entry)
    {
        var handler = entry.Handler;
        var alias = entry.User.AliasOrUID;
        if (string.IsNullOrWhiteSpace(alias))
        {
            alias = entry.Ident.UserId;
        }

        var displayName = !string.IsNullOrWhiteSpace(handler?.PlayerName)
            ? handler!.PlayerName!
            : alias;

        var note = _serverConfigurationManager.GetNoteForUid(entry.Ident.UserId) ?? string.Empty;
        var isPaused = entry.SelfPermissions.IsPaused();

        return new PairUiEntry(
            entry,
            alias,
            displayName,
            note,
            entry.IsVisible,
            entry.IsOnline,
            entry.IsDirectlyPaired,
            entry.IsOneSided,
            entry.HasAnyConnection,
            isPaused,
            entry.SelfPermissions,
            entry.OtherPermissions,
            entry.PairStatus,
            handler?.LastAppliedDataBytes ?? -1,
            handler?.LastAppliedDataTris ?? -1,
            handler?.LastAppliedApproximateVRAMBytes ?? -1,
            handler?.LastAppliedApproximateEffectiveVRAMBytes ?? -1,
            handler);
    }
}