using Fantasy;
using Fantasy.Async;
using Fantasy.Entitas.Interface;
using Fantasy.Network;
using Fantasy.Platform.Net;
using NB.Common;

// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract

namespace NB.Gate;

public class GateUnitDestroySystem : DestroySystem<GateUnit>
{
    protected override void Destroy(GateUnit self)
    {
        self.AccountID = 0;
        self.Region = 0;
        self.SceneRoutes.Clear();
        self.RoomCode = string.Empty;
    }
}

public static class GateUnitSystem
{
    #region Address

    public static void RemoveAddress(this GateUnit self, int routType)
    {
        self.SceneRoutes.Remove(routType);
    }

    public static void AddAddress(this GateUnit self, int routType, long routeId)
    {
        self.SceneRoutes[routType] = routeId;
    }

    public static long GetAddress(this GateUnit self, int routType)
    {
        return self.SceneRoutes.GetValueOrDefault(routType, 0);
    }

    #endregion


    #region 上线

    public static async FTask<uint> Online(this GateUnit self, params int[] routeType)
    {
        if (routeType != null && routeType.Length > 0)
        {
            foreach (var route in routeType)
            {
                var ret = await self.Online(route);
                if (ret != ErrorCode.Successful) return ret;
            }
        }

        return ErrorCode.Successful;
    }

    public static async FTask<uint> Online(this GateUnit self, int routeType, SceneConfig? sceneConfig = null)
    {
        Session session = self.Session;
        var routeComponent = session.GetComponent<RouteComponent>();
        if (routeComponent == null)
        {
            routeComponent = session.AddComponent<RouteComponent>();
        }

        if (sceneConfig == null)
        {
            sceneConfig = SceneConfigHelper.GetConfigByRouteType(routeType);
        }

        var gameRouteId = sceneConfig.RouteId;

        var gameResponse = (G2Common_EnterResponse)await self.Scene.NetworkMessagingComponent.CallInnerRoute(
            gameRouteId, new G2Common_EnterRequest()
            {
                AccountId = self.AccountID,
                GateRouteId = session.RuntimeId
            });

        if (gameResponse.ErrorCode != 0)
        {
            return gameResponse.ErrorCode;
        }

        routeComponent.RemoveAddress(routeType);
        routeComponent.AddAddress(routeType, gameResponse.UnitRouteId);
        self.AddAddress(routeType, gameResponse.UnitRouteId);
        self.AddAddress(sceneConfig.SceneType, gameRouteId);

        return ErrorCode.Successful;
    }

    #endregion

    #region 下线

    public static async FTask<uint> Offline(this GateUnit self, long sessionId, params int[] routeType)
    {
        if (routeType != null && routeType.Length > 0)
        {
            foreach (var route in routeType)
            {
                var ret = await self.Offline(sessionId, route);
                if (ret != ErrorCode.Successful) return ret;
            }
        }

        return ErrorCode.Successful;
    }

    public static async FTask<uint> Offline(this GateUnit self, long sessionId, int routeType)
    {
        var sceneConfig = SceneConfigHelper.GetConfigByRouteType(routeType);
        var sceneRouteId = sceneConfig.RouteId;
        if (sceneRouteId < 1) return ErrorCode.Successful;
        for (int i = 0; i < 10; i++)
        {
            var gameResponse = (Common2G_ExitResponse)await self.Scene.NetworkMessagingComponent.CallInnerRoute(
                sceneRouteId, new G2Common_ExitRequest()
                {
                    AccountId = self.AccountID,
                    GateRouteId = sessionId
                });
            if (gameResponse.ErrorCode == 0)
            {
                //TODO:这里需要清理掉记录的数据
                self.RemoveAddress(routeType);
                self.RemoveAddress(sceneConfig.SceneType);
                return ErrorCode.Successful;
            }
        }

        Log.Error($"重试多次还是退出失败，需检查,sessionId={sessionId} route={routeType}");
        return ErrorCode.ErrServer;
    }

    #endregion
}