using Sandbox.ModAPI.Ingame;
using SpaceEngineers.Game.ModAPI.Ingame;
using System.Collections.Generic;
using VRageMath;

namespace IngameScript
{
    partial class Program
    {
        public class AirZone
        {
            public string Name { get; private set; }

            public bool Triggered
            {
                get
                {
                    foreach (IMyAirVent vent in Vents)
                    {
                        if (vent.GetOxygenLevel() < TriggerLevel || vent.Status == VentStatus.Depressurized) return true;
                    }
                    return false;
                }
            }

            public float OxygenLevel
            {
                get
                {
                    float ret = 100F;
                    foreach (IMyAirVent vent in Vents)
                    {
                        if (vent.GetOxygenLevel() < ret) ret = vent.GetOxygenLevel();
                    }
                    return ret;
                }
            }

            public List<IMyAirVent> Vents { get; } = new List<IMyAirVent>();

            private Program _program;

            // private List<IMyTextSurface> _displays = new List<IMyTextSurface>(); // TODO: add single-zone displays
            private List<IMyLightingBlock> _lights = new List<IMyLightingBlock>();
            private List<AirDoor> _doors = new List<AirDoor>();
            private PrefixedConsole _console;
            private ActionSequence _sealBulkheads; // actions to perform when the pressure alarm is triggered

            private const float TriggerLevel = 0.75F;

            public AirZone(Program program, string zoneName)
            {
                Name = zoneName;
                _program = program;
                _console = new PrefixedConsole(_program.Console, Name);
                _sealBulkheads = new ActionSequence(Name);
            }

            public void AddDoor(AirDoor door)
            {
                _doors.Add(door);
                IMyDoor doorBlock = door.Door;
                _sealBulkheads.Add(0, new BlockActionDoor(
                    doorBlock,
                    BlockActionDoor.DoorAction.Close,
                    true
                ));
            }

            public void AddBlock(IMyTerminalBlock block)
            {
                if (block is IMyAirVent)
                {
                    Vents.Add(block as IMyAirVent);
                }
                else if (block is IMyLightingBlock)
                {
                    _lights.Add(block as IMyLightingBlock);
                }
                else
                {
                    _console.Print("Tried to add incompatible block '{block.CustomName}'");
                }
                // TODO: support for arbitrary (sub-)sequences here could be powerful
            }

            // This enumerator should run forever.
            public IEnumerator<bool> Monitor()
            {
                while (true)
                {
                    if (Triggered == true)
                    {
                        _console.Print($"Low pressure alarm triggered.");
                        // close the doors
                        IEnumerator<bool> job = _sealBulkheads.Run();
                        while (job.MoveNext())
                        {
                            // It would be nice if the API had UpdateFrequency.Once10, e.g. "re-run in 10 ticks and then clear the flag"
                            // We'll just monitor every tick instead.
                            setTriggeredStates();
                            _program.Runtime.UpdateFrequency |= UpdateFrequency.Once;
                            yield return true;
                        }
                        job.Dispose();

                        while (Triggered)
                        {
                            setTriggeredStates();
                            yield return true;
                        }
                        _console.Print("Air pressure returned to safe levels.");
                    }

                    yield return true;
                }
            }

            private void setTriggeredStates()
            {
                foreach (IMyLightingBlock light in _lights) light.Color = Color.Red;
                foreach (AirDoor door in _doors) door.Triggered = true;
            }
        }
    }
}