using Sandbox.Game.Entities.Cube;
using Sandbox.Game.EntityComponents;
//using Sandbox.ModAPI;
using Sandbox.ModAPI.Ingame;
using Sandbox.ModAPI.Interfaces;

using SpaceEngineers.Game.ModAPI.Ingame;

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;

using VRage;
using VRage.Collections;
using VRage.Game;
using VRage.Game.Components;
using VRage.Game.GUI.TextPanel;
using VRage.Game.ModAPI.Ingame;
using VRage.Game.ModAPI.Ingame.Utilities;
using VRage.Game.ObjectBuilders.Definitions;

using VRageMath;

namespace IngameScript
{
    partial class Program : MyGridProgram
    {
        const string MISSILE_GRID_PREFIX = "[PM]";

        const float EPSILON = 0.05f;
        const double DELAY_BEFORE_TRAVELLING_MODE = 3000; // [ms].
        const double AUTO_DESTRUCTION_AFTER = 60000; // [ms] (1 min). Or if the hydrogen tank is empty.


        enum State
        {
            NORMAL,
            LAUNCHING,
            TRAVELLING,
        }

        State currentState = State.NORMAL;

        readonly Output output;

        int tickFromStart;
        IMyThrust forwardThruster;        
        IMyFlightMovementBlock aiMove;
        IMyOffensiveCombatBlock aiCombat;
        IMySensorBlock sensor;
        List<IMyWarhead> warheads = new List<IMyWarhead>();
        IMyGasTank gasTank;
        IMyLightingBlock light;

        public Program()
        {
            var output = this.Me.GetSurface(0);
            this.output = new Output(output);

            this.output.Print("Missile controller system starting...");

            this.Runtime.UpdateFrequency = UpdateFrequency.Update10;

            this.output.Print("Missile controller system started");
        }

        void UpdateState10()
        {
            if (this.forwardThruster == null)
                this.forwardThruster = this.GridTerminalSystem.GetBlockWithName("[PM] Hydrogen Thruster 01") as IMyThrust;
            if (this.forwardThruster == null)
            {
                this.output.Print("Error: Cannot find forward thruster");
                return;
            }

            if (this.aiMove == null)
                this.aiMove = this.GridTerminalSystem.GetBlockWithName("[PM] AI Flight (Move)") as IMyFlightMovementBlock;
            if (this.aiMove == null)
            {
                this.output.Print("Error: Cannot find AI move");
                return;
            }

            if (this.aiCombat == null)
                this.aiCombat = this.GridTerminalSystem.GetBlockWithName("[PM] AI Offensive (Combat)") as IMyOffensiveCombatBlock;
            if (this.aiCombat == null)
            {
                this.output.Print("Error: Cannot find AI combat");
                return;
            }

            if (this.sensor == null)
                this.sensor = this.GridTerminalSystem.GetBlockWithName("[PM] Sensor") as IMySensorBlock;
            if (this.sensor == null)
            {
                this.output.Print("Error: Cannot find sensor");
                return;
            }

            if (this.warheads.Count == 0)
                this.GridTerminalSystem.GetBlockGroupWithName("[PM] Warheads").GetBlocksOfType(this.warheads);
            if (this.warheads.Count == 0)
            {
                this.output.Print("Error: Cannot find any warhead");
                return;
            }

            if (this.gasTank == null)
                this.gasTank = this.GridTerminalSystem.GetBlockWithName("[PM] Hydrogen Tank") as IMyGasTank;
            if (this.gasTank == null)
            {
                this.output.Print("Error: Cannot find gas tank");
                return;
            }

            if (this.light == null)
                this.light = this.GridTerminalSystem.GetBlockWithName("[PM] Light") as IMyLightingBlock;
            if (this.light == null)
            {
                this.output.Print("Error: Cannot find light");
                return;
            }

            switch (this.currentState)
            {
                case State.LAUNCHING:
                    // this.output.Print($"Tick: {this.tickFromStart}");
                    //this.forwardThruster.ove
                    this.forwardThruster.ThrustOverridePercentage = 1;
                    if (this.MsSinceLaunch > DELAY_BEFORE_TRAVELLING_MODE)
                    {
                        this.forwardThruster.ThrustOverridePercentage = 0;
                        this.aiMove.Enabled = true;
                        this.aiCombat.Enabled = true;

                        foreach (var warhead in this.warheads)
                            warhead.IsArmed = true;

                        this.output.Print($"Travelling mode");
                        this.currentState = State.TRAVELLING;
                    }
                    break;

                case State.TRAVELLING:
                    var detectedEntity = this.sensor.LastDetectedEntity;

                    if (this.MsSinceLaunch > AUTO_DESTRUCTION_AFTER - 3000)
                        this.light.BlinkIntervalSeconds = 0.5f;

                    if (this.gasTank.FilledRatio <= EPSILON || detectedEntity.Type != MyDetectedEntityType.None || this.MsSinceLaunch > AUTO_DESTRUCTION_AFTER)
                    { 
                        Detonate();
                    }
                    break;

                case State.NORMAL:
                    break; // Nothing;
            }
        }

        void Detonate()
        {
            foreach (var warhead in this.warheads)
                warhead.Detonate();
        }

        public void Save()
        {
        }

        double MsSinceLaunch
        {
            get { return (double)this.tickFromStart / 60 * 1000; }
        }

        public void Main(string argument, UpdateType updateSource)
        {
            if ((updateSource & UpdateType.Update10) != 0)
            {
                this.tickFromStart += 10;
                this.UpdateState10();
            }
            else if ((updateSource & (UpdateType.Script | UpdateType.Terminal | UpdateType.Trigger)) != 0)
            {
                switch (argument)
                {
                    case "START":
                        this.output.Print("Launching mode");
                        this.tickFromStart = 0;
                        this.currentState = State.LAUNCHING;
                        break;

                    default:
                        this.output.Print($"Uknown command: {argument}");
                        break;
                }
            }
        }
    }
}
