using System;
using System.Collections.Generic;
using System.Numerics;
using Coroutine;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MLEM.Cameras;
using MLEM.Startup;

namespace TouchyTickets {
    public class GameImpl : MlemGame {

        public static GameImpl Instance { get; private set; }
        public readonly ISet<Upgrade> AppliedUpgrades = new HashSet<Upgrade>();
        public readonly Platform Platform;
        public BigInteger Tickets;
        public int TimesRestarted;
        public int Stars;
        public ParkMap Map;
        public Tutorial Tutorial { get; private set; }
        public Camera Camera { get; private set; }
        public Ui Ui { get; private set; }
        public bool DrawMap;
        public DateTime LastUpdate;
        private double saveCounter;

        public GameImpl(Platform platform) {
            this.Platform = platform;
            Instance = this;
        }

        protected override void LoadContent() {
            base.LoadContent();
            Options.Load();
            
            // start the load sequence
            Ui.SetupUiSystem(this.UiSystem);
            CoroutineHandler.Start(Ui.DisplaySplash(this.LoadGame));
        }

        private void LoadGame() {
            // set up analytics
            var settings = new Dictionary<string, object>();
            settings["InfoLog"] = true;
            settings["VerboseLog"] = true;
            settings["SubmitErrors"] = true;
            settings["ResourceCurrencies"] = new[] {"Tickets", "Stars"};
            settings["ResourceItemTypes"] = new[] {"Attraction", "Restart", "Upgrade", "Modifier"};
            // ios comes first, then android. For now they're the same
            settings["GameKey"] = new[] {"cc18de06eebbc5d5e987c384fcd28000", "cc18de06eebbc5d5e987c384fcd28000"};
            settings["SecretKey"] = new[] {"82ca1a930ee38e2383ffb02db7631e16033b511d", "82ca1a930ee38e2383ffb02db7631e16033b511d"};
            this.Platform.SetupAnalytics(settings);
            this.Platform.SetupAds();

            this.Tutorial = new Tutorial();

            if (!SaveHandler.Load(this))
                this.Map = new ParkMap(20, 20);

            // load other stuff
            this.Ui = new Ui(this.UiSystem);
            this.Camera = new Camera(this.GraphicsDevice) {
                Scale = 4,
                AutoScaleWithScreen = true,
                AutoScaleReferenceSize = new Point(720, 1280),
                MaxScale = 24,
                MinScale = 2
            };
        }

        protected override void DoUpdate(GameTime gameTime) {
            base.DoUpdate(gameTime);

            if (this.Map != null) {
                var now = DateTime.Now;
                if (this.LastUpdate != default) {
                    var passed = now - this.LastUpdate;
                    // if more than 1 second passed, the app is minimized or a save was loaded, so we penalize
                    if (passed.TotalSeconds >= 1)
                        passed = new TimeSpan(passed.Ticks / 2);
                    this.Map.Update(gameTime, passed);
                }
                this.LastUpdate = now;

                // save every 3 seconds
                this.saveCounter += gameTime.ElapsedGameTime.TotalSeconds;
                if (this.saveCounter >= 3) {
                    this.saveCounter = 0;
                    SaveHandler.Save(this);
                }
            }

            this.Ui?.Update(gameTime);
            this.Tutorial?.Update(this);
        }

        protected override void DoDraw(GameTime gameTime) {
            this.GraphicsDevice.Clear(Color.Black);
            if (this.DrawMap) {
                this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, transformMatrix: this.Camera.ViewMatrix);
                this.Map.Draw(gameTime, this.SpriteBatch, Vector2.Zero, 1, 1, true, this.Camera.GetVisibleRectangle());
                this.SpriteBatch.End();
            }
            base.DoDraw(gameTime);
        }

        public BigInteger GetStarPrice() {
            return 1000000000 * BigInteger.Pow(10, this.TimesRestarted);
        }

        public int GetMaxStars() {
            return 3 * (this.TimesRestarted + 1);
        }

        public int GetBuyableStars() {
            return Math.Min(this.GetMaxStars(), (int) (this.Tickets / this.GetStarPrice()));
        }

    }
}