using CommonAI;
using CommonAI.RTS.Manhattan;
using CommonAI.Zone;
using CommonAI.Zone.Helper;
using CommonAI.Zone.ZoneEditor;
using CommonAI.ZoneClient;
using ET;
using System;
using System.Collections.Generic;
using System.IO;
using XmdsCommon.EditorData;
using XmdsCommon.Plugin;
using Log = ET.Log;


public class BattleResourceMgr : Singleton<BattleResourceMgr>, ISingletonAwake
{
    public EditorTemplates GameEditorTemplates;
    public SynchronizedBattleCodec BattleMsgDecoder;

    public void Awake()
    {
        InitAsync().Coroutine();
    }

    public async ETTask InitAsync()
    {
        GameEditorTemplates = new EditorTemplates("", TemplateManager.MessageCodec);
        TemplateManager.setFactory(new XmdsUnityLocalFactory());

        var op = await YooAssetProxy.GetRawFileAsync("GameEditor_e1");
        var e1 = op.GetRawBytes();
        if (e1 == null)
        {
            Log.Error("not found GameEditor e1 data.");
            return;
        }
        Log.Debug("to load e1");

        //var zippedStream = new MemoryStream(e1);
        var binLoadStream = new MemoryStream(e1);
        //LZMAHelper.Decompress(zippedStream, e1.Length, binLoadStream);
        var binMemDic = InitBinFilePostionDic(binLoadStream);

        var editorTemplates = this.GameEditorTemplates;
        editorTemplates.LoadAllCFG(binMemDic["config"]);
        LoadTemplates<CommonAI.Zone.UnitInfo>(editorTemplates, binMemDic["units"]);
        LoadTemplates<SkillTemplate>(editorTemplates, binMemDic["skills"]);
        LoadTemplates<SpellTemplate>(editorTemplates, binMemDic["spells"]);
        LoadTemplates<BuffTemplate>(editorTemplates, binMemDic["buffs"]);
        LoadTemplates<ItemTemplate>(editorTemplates, binMemDic["items"]);
        LoadTemplates<UnitEventTemplate>(editorTemplates, binMemDic["unit_events"]);
        LoadTemplates<UnitTriggerTemplate>(editorTemplates, binMemDic["unit_triggers"]);
        LoadSceneSnapData(binMemDic["snaps"]);
        LoadNewSceneSnapData(binMemDic["newsnaps"]);

        TemplateManager.Formula.InitPluginsData(editorTemplates);
        editorTemplates.Templates.RehashAll();
        Log.Info("load e1 end");

        op = await YooAssetProxy.GetRawFileAsync("GameEditor_ex");
        var ex = op.GetRawBytes();
        if (ex == null)
        {
            Log.Error("not found GameEditor ex data.");
            return;
        }
        editorTemplates.SetSceneDataLoader(new SceneDataLoader(ex));
        Log.Info("load ex end");
        this.BattleMsgDecoder = new SynchronizedBattleCodec(this.GameEditorTemplates.Templates);
    }

    private static Dictionary<string, MemoryStream> InitBinFilePostionDic(MemoryStream binLoadStream)
    {
        var binMemDic = new Dictionary<string, MemoryStream>();
        var br = new BinaryReader(binLoadStream);
        binLoadStream.Position = 0;
        var count = br.ReadByte();
        var names = new string[count];
        var sizes = new int[count];
        for (int i = 0; i < count; i++)
        {
            names[i] = br.ReadString();
            sizes[i] = br.ReadInt32();
        }

        var offset = (int) binLoadStream.Position;
        for (int i = 0; i < count; i++)
        {
            var name = names[i];
            var size = sizes[i];
            binMemDic[name] = new MemoryStream();
            binLoadStream.Position = offset;
            binLoadStream.CopyTo(binMemDic[name], size);
            binMemDic[name].Position = 0;
            offset += size;
        }

        return binMemDic;
    }

    public static void LoadTemplates<T>(EditorTemplates template, Stream stream) where T : class, ITemplateData
    {
        try
        {
            var br = new BinaryReader(stream);
            var n = br.ReadInt32();
            for (var i = 0; i < n; i++)
            {
                var name = br.ReadString();
                var len = br.ReadInt32();
                var rpos = stream.Position;
                try
                {
                    template.LoadTemplate<T>(stream);
                }
                catch (Exception err)
                {
                    Log.Error("LoadTemplate:{0},{1}", typeof(T), name);
                    Log.Error(err);
                }
                finally
                {
                    stream.Position = rpos + len;
                }
            }
        }
        catch (Exception e)
        {
            Log.Error(e);
        }
    }

    public static void LoadSceneSnapData(Stream stream)
    {
        try
        {
            var br = new BinaryReader(stream);
            var n = br.ReadInt32();
            for (var i = 0; i < n; i++)
            {
                var _id = br.ReadInt32();
                var _len = br.ReadInt32();
                var _dat = br.ReadBytes(_len);
                try
                {
                    SceneSnapManager.LoadSceneSnapData(_id, _dat);
                }
                catch (Exception err)
                {
                    Log.Error(err);
                }
            }
        }
        catch (Exception e)
        {
            Log.Error(e);
        }
    }

    public static void LoadNewSceneSnapData(Stream stream)
    {
        try
        {
            var br = new BinaryReader(stream);
            var n = br.ReadInt32();
            for (var i = 0; i < n; i++)
            {
                var _id = br.ReadInt32();
                var _len = br.ReadInt32();
                var _dat = br.ReadBytes(_len);
                try
                {
                    SceneSnapManager.LoadBinUnitSnapData(_id, _dat);
                }
                catch (Exception err)
                {
                    Log.Error(err);
                }
            }
        }
        catch (Exception e)
        {
            Log.Error(e);
        }
    }

    public class XmdsUnityLocalFactory : XmdsZoneFactory
    {
        public override ZoneLayer CreateClientZoneLayer(EditorTemplates templates, ILayerClient listener)
        {
            return new HZUnityZoneLayer(templates, listener);
        }
    }

    //-----------------------------------------------------------------------------------------------------
    #region 接入Untiy寻路
    public class HZUnityZoneLayer : XmdsCommon.ZoneClient.HZZoneLayer
    {
        public HZUnityZoneLayer(EditorTemplates dataroot, ILayerClient client)
            : base(dataroot, client)
        {
        }

        protected override void InitTerrain(ClientEnterScene msg, out ZoneManhattanMap terrain_data,
            out AstarManhattan path_finder, out ManhattanMapAreaGenerator area_gen)
        {
            var data = TerrainSrc.Clone() as ZoneInfo;
            terrain_data = new ZoneManhattanMap(data, Templates.TerrainDefinition);
            path_finder = new HZUnityAstarManhattan(msg.sceneID, terrain_data, true, 0);
            area_gen = new ManhattanMapAreaGenerator(terrain_data.Data);
            //this.Data.Terrain = null;
            this.IsShareTerrain = false;
            this.IsIgnoreTerrainTouch = false;
        }
    }

    public class HZUnityAstarManhattan : AstarManhattan
    {
        public HZUnityAstarManhattan(int sceneId, IManhattanMap map_data, bool inclined = true, int space_size = 0)
            : base(sceneId, map_data, inclined, space_size)
        {
        }

        public override FindPathResult findPath(float sx, float sy, float dx, float dy, out MWayPoint ret,
            bool optimize = true)
        {
            // TODO 接入Untiy寻路
            // NavMesh.CalculatePath();
            return base.findPath(sx, sy, dx, dy, out ret, optimize);
        }
    }

    #endregion
}