// WingsEmu
// 
// Developed by NosWings Team

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using PhoenixLib.Logging;
using WingsEmu.Core.Extensions;
using WingsEmu.DTOs.ServerDatas;
using WingsEmu.Game.Battle;
using WingsEmu.Plugins.BasicImplementations.ServerConfigs.ImportObjects;
using WingsEmu.Plugins.BasicImplementations.ServerConfigs.ImportObjects.Teleporters;
using WingsEmu.Plugins.BasicImplementations.ServerConfigs.Persistence;

namespace WingsEmu.Plugins.BasicImplementations.ServerConfigs;

public class TeleporterManager : ITeleporterManager
{
    private readonly IEnumerable<TeleporterImportFile> _teleporterConfigurations;
    private readonly Dictionary<long, List<TeleporterDTO>> _teleporters = new();
    private readonly Dictionary<long, List<TeleporterDTO>> _teleportersByNpcId = new();

    public TeleporterManager(IEnumerable<TeleporterImportFile> teleporterConfigurations) => _teleporterConfigurations = teleporterConfigurations;

    public async Task InitializeAsync()
    {
        List<TeleporterDTO> allTeleporters = null;
        bool dbFirst = ParserDataPostgresReader.DbFirstEnabled;
        bool strictDbOnly = ParserDataPostgresReader.StrictDbOnlyEnabled;

        if (dbFirst)
        {
            try
            {
                allTeleporters = ParserDataPostgresReader.LoadTeleporters();
                Log.Info($"[DB_FIRST] Loaded {allTeleporters.Count} map_teleporters from database");
            }
            catch (Exception e)
            {
                if (strictDbOnly)
                {
                    throw new InvalidOperationException("DB_FIRST/STRICT_DB_ONLY enabled but failed to load map_teleporters from database.", e);
                }

                Log.Error("[DB_FIRST] Could not load map_teleporters from database", e);
            }

            if (strictDbOnly && (allTeleporters == null || allTeleporters.Count == 0))
            {
                throw new InvalidOperationException("DB_FIRST/STRICT_DB_ONLY enabled but no map_teleporters were loaded from database.");
            }
        }

        if (allTeleporters == null || allTeleporters.Count == 0)
        {
            allTeleporters = new List<TeleporterDTO>();
            foreach (TeleporterImportFile file in _teleporterConfigurations)
            {
                allTeleporters.AddRange(file.Teleporters.Select(s =>
                {
                    s.MapId = file.MapId;
                    return s.ToDto();
                }));
            }

            ParserDataPostgresSync.SyncTeleporters(allTeleporters);
        }

        foreach (IGrouping<int, TeleporterDTO> group in allTeleporters.GroupBy(s => s.MapId))
        {
            _teleporters[group.Key] = group.ToList();
        }

        foreach (TeleporterDTO teleporter in allTeleporters)
        {
            if (!_teleportersByNpcId.TryGetValue(teleporter.MapNpcId, out List<TeleporterDTO> teleporterDtos))
            {
                teleporterDtos = new List<TeleporterDTO>();
                _teleportersByNpcId[teleporter.MapNpcId] = teleporterDtos;
            }

            teleporterDtos.Add(teleporter);
        }

        Log.Info($"[DATABASE] Loaded {allTeleporters.Count.ToString()} teleporters.");
    }

    public IReadOnlyList<TeleporterDTO> GetTeleportByNpcId(long npcId) => _teleportersByNpcId.GetOrDefault(npcId);
    public IReadOnlyList<TeleporterDTO> GetTeleportByMapId(int mapId) => _teleporters.GetOrDefault(mapId);
}
