using System;
using System.Net;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Monocle;
using Celeste.Mod.teleportingEsoterically.Entities;
using MonoMod.Cil;
using System.Xml;
using Mono.Cecil.Cil;

namespace Celeste.Mod.teleportingEsoterically;

public class teleportingEsotericallyModule : EverestModule
{
    public static teleportingEsotericallyModule Instance { get; private set; }

    public override Type SettingsType => typeof(teleportingEsotericallyModuleSettings);
    public static teleportingEsotericallyModuleSettings Settings => (teleportingEsotericallyModuleSettings)Instance._Settings;

    public override Type SessionType => typeof(teleportingEsotericallyModuleSession);
    public static teleportingEsotericallyModuleSession Session => (teleportingEsotericallyModuleSession)Instance._Session;

    public override Type SaveDataType => typeof(teleportingEsotericallyModuleSaveData);
    public static teleportingEsotericallyModuleSaveData SaveData => (teleportingEsotericallyModuleSaveData)Instance._SaveData;


    public static bool LOENN_IS_OPEN = true;
    private const string TOP_FOLDER = "ModFiles";
    private const string MOD_FOLDER = "aletris_teleportingEsoterically";
    private List<RCEndPoint> RCEndPoints = new List<RCEndPoint>();

    public teleportingEsotericallyModule()
    {
        Instance = this;
#if DEBUG
        // debug builds use verbose logging
        Logger.SetLogLevel(nameof(teleportingEsotericallyModule), LogLevel.Verbose);
#else
        // release builds use info logging to reduce spam in log files
        Logger.SetLogLevel(nameof(teleportingEsotericallyModule), LogLevel.Info);
#endif
    }
    public static void RoomClearSession_SetFlag(On.Celeste.Session.orig_SetFlag orig, Session self, string flag, bool setTo)
    {
        var cont = Engine.Scene.Tracker.GetEntity<RoomClearController>();
        if (cont != null && setTo == true)
        {
            foreach (string item in cont.flagstodingaling.Split(','))
            {
                if (item != flag) continue;
                foreach (string sndevent in cont.audioevents.Split(','))
                {
                    Audio.Play(sndevent, "fade", 0.5f);
                }
            }
        }
        orig(self, flag, setTo);
    }


    public static void IL_Render(ILContext il)
    {
        ILCursor cursor = new ILCursor(il);
        while (cursor.TryGotoNext(MoveType.After, instr => instr.MatchLdstr("areaselect/card")))
        {
            cursor.Emit(OpCodes.Ldarg_0);
            cursor.EmitDelegate(ChangeTexture);
        }
        cursor.Index = 0;
        while (cursor.TryGotoNext(MoveType.After, instr => instr.MatchLdstr("areaselect/cardtop")))
        {
            cursor.Emit(OpCodes.Ldarg_0);
            cursor.EmitDelegate(ChangeTopTexture);
        }
    }

    private static string ChangeTexture(string mtexture, OuiChapterPanel self)
    {
        if (!self.DisplayedStats.Modes[(int)self.Area.Mode].Completed) return mtexture;
        Dictionary<char, XmlElement> dictionary = new Dictionary<char, XmlElement>();
        XmlDocument doc = new();
        doc.Load(Everest.Content.Get("Graphics/aletris/esoterica/MapSignatures").Stream);
        foreach (XmlElement obj in doc.SelectNodes("//Map"))
        {
            string mapsid = obj.GetAttribute("SID");
            if (AreaData.Get(self.Area).SID != mapsid)
            {
                continue;
            }
            else return obj.GetAttribute("card");
        }
        return mtexture;
    }

    private static string ChangeTopTexture(string mtexture2, OuiChapterPanel self)
    {
        if (!self.DisplayedStats.Modes[(int)self.Area.Mode].Completed) return mtexture2;
        Dictionary<char, XmlElement> dictionary = new Dictionary<char, XmlElement>();
        XmlDocument doc = new();
        doc.Load(Everest.Content.Get("Graphics/aletris/esoterica/MapSignatures").Stream);
        foreach (XmlElement obj in doc.SelectNodes("//Map"))
        {
            string mapsid = obj.GetAttribute("SID");
            if (AreaData.Get(self.Area).SID != mapsid)
            {
                continue;
            }
            else return obj.GetAttribute("cardtop");
        }
        return mtexture2;
    }

    public override void Load() 
    {
        On.Celeste.Session.SetFlag += RoomClearSession_SetFlag;
        IL.Celeste.OuiChapterPanel.Render += IL_Render;


        RCEndPoints.Add(new RCEndPoint // what the fuck am i doing here
        {
            Path = "/teleportingEsoterically/LoennIsOpen",
            Name = "Loenn is Open",
            InfoHTML = "This is used by Aurora's Lönn Plugin to notify the c# code that loenn is open and debugrc works. (Thanks aurora!)",
            Handle = delegate (HttpListenerContext c)
            {
                LOENN_IS_OPEN = true;
                Everest.DebugRC.Write(c, "OK");
            }
        });

        foreach (RCEndPoint rcEndPoint in RCEndPoints)
        {
            Everest.DebugRC.EndPoints.Add(rcEndPoint);
        }
    }

    public override void Unload()
    {
        On.Celeste.Session.SetFlag -= RoomClearSession_SetFlag;
        IL.Celeste.OuiChapterPanel.Render += IL_Render;
        // TODO: unapply any hooks applied in Load()
    }
}