using Sandbox.ModAPI.Ingame;
using SpaceEngineers.Game.ModAPI.Ingame;
using System.Collections.Generic;
using VRage.Game.ModAPI.Ingame.Utilities;

namespace IngameScript
{
    public partial class Program : MyGridProgram, IConsoleProgram
    {
        public MyIni Ini { get; } = new MyIni();
        public IConsole Console { get; private set; }

        private Dictionary<string, Airlock> _airlocks = new Dictionary<string, Airlock>();
        private List<IEnumerator<bool>> _jobs = new List<IEnumerator<bool>>();
        private MyCommandLine _cli = new MyCommandLine();

        public Program()
        {
            Console = new MainConsole(this, "Airlock Controller");

            List<IMyTerminalBlock> airlockBlocks = new List<IMyTerminalBlock>();
            GridTerminalSystem.GetBlocksOfType(airlockBlocks, blockFilter);
            IMyAirVent referenceVent = null;
            foreach (IMyTerminalBlock block in airlockBlocks)
            {
                Ini.TryParse(block.CustomData, "airlock");

                // TODO: redundant reference vents would be awesome. Everyone loves redundancy
                if (block is IMyAirVent && Ini.Get("airlock", "reference").ToBoolean())
                {
                    if (referenceVent != null)
                    {
                        Console.Print("Found multiple reference vents. Only the first one will be used.");
                        continue;
                    }

                    referenceVent = block as IMyAirVent;
                    Console.Print($"Found reference vent {block.CustomName}.");
                    continue;
                }

                string airlockName = Ini.Get("airlock", "id").ToString();
                if (!_airlocks.ContainsKey(airlockName))
                {
                    _airlocks[airlockName] = new Airlock(airlockName, this);
                }

                _airlocks[airlockName].AddBlock(block);
            }

            if (referenceVent != null) foreach (Airlock airlock in _airlocks.Values) { airlock.ReferenceVent = referenceVent; }

            Console.Print($"Found {_airlocks.Count} airlocks.");
            Console.UpdateTickCount();
        }

        public void Main(string argument, UpdateType updateSource)
        {
            Console.UpdateTickCount();

            if (updateSource == UpdateType.Trigger || updateSource == UpdateType.Terminal)
            {
                _cli.TryParse(argument);
                if (_cli.ArgumentCount == 0) Console.Print("Airlock ID not provided.");
                else
                {
                    string airlockName = _cli.Argument(0);
                    if (!_airlocks.ContainsKey(airlockName)) Console.Print($"Airlock ID '{airlockName}' not found.");
                    else if (!_airlocks[airlockName].Functional) Console.Print($"Airlock '{airlockName}' is not functional.");
                    else
                    {
                        _jobs.Add(_airlocks[airlockName].CycleAirlock());
                        Runtime.UpdateFrequency |= UpdateFrequency.Update10;
                    }
                }
            }

            for (int i = 0; i < _jobs.Count; i++)
            {
                IEnumerator<bool> job = _jobs[i];
                if (job.MoveNext()) continue;
                job.Dispose();
                _jobs.Remove(job);
                i--;
                Console.Print("Job Removed From Queue.");
            }

            if (_jobs.Count == 0) Runtime.UpdateFrequency = UpdateFrequency.None;
        }

        private bool blockFilter(IMyTerminalBlock block)
        {
            return block.IsSameConstructAs(this.Me) && MyIni.HasSection(block.CustomData, "airlock");
        }
    }
}