using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using MLEM.Textures;
using Newtonsoft.Json;
using static TouchyTickets.Attractions.AttractionFlags;

namespace TouchyTickets.Attractions {
    [JsonConverter(typeof(Converter))]
    public class AttractionType {

        public static readonly Dictionary<string, AttractionType> Attractions = new Dictionary<string, AttractionType>();
        public static readonly AttractionType Carousel = Register(new AttractionType("Carousel", RectArea(1, 1), new Rectangle(0, 0, 1, 1), 0.5F, 50, Relaxed | Cars | Small));
        public static readonly AttractionType MirrorHouse = Register(new AttractionType("MirrorHouse", RectArea(1, 1), new Rectangle(3, 0, 1, 1), 1, 150, Relaxed | Walking | NonTechnology | Small));
        public static readonly AttractionType FoodCourt = Register(new AttractionType("FoodCourt", RectArea(2, 1), new Rectangle(1, 0, 2, 1), 2F, 300, None));
        public static readonly AttractionType SpiralSlide = Register(new AttractionType("SpiralSlide", RectArea(1, 2), new Rectangle(5, 0, 1, 2), 4, 1200, Relaxed | Walking));
        public static readonly AttractionType HedgeMaze = Register(new AttractionType("HedgeMaze", RectArea(2, 2), new Rectangle(3, 3, 2, 2), 8, 2500, Relaxed | Walking | NonTechnology));
        public static readonly AttractionType FerrisWheel = Register(new AttractionType("FerrisWheel", RectArea(2, 2), new Rectangle(0, 1, 2, 2), 12, 4000, Relaxed | Cars));
        public static readonly AttractionType FreefallCoaster = Register(new AttractionType("FreefallCoaster", new[,] {{true, false, true}, {true, true, true}}, new Rectangle(6, 0, 3, 2), 24, 8000, FastCars));
        public static readonly AttractionType HauntedHouse = Register(new AttractionType("HauntedHouse", RectArea(2, 2), new Rectangle(3, 5, 2, 2), 30, 12000, FastCars));
        public static readonly AttractionType GoKarts = Register(new AttractionType("GoKarts", RectArea(2, 2), new Rectangle(5, 2, 2, 2), 50, 24000, Cars | Relaxed));
        public static readonly AttractionType MiniGolf = Register(new AttractionType("MiniGolf", RectArea(2, 3), new Rectangle(9, 0, 2, 3), 75, 35000, Relaxed | Walking | NonTechnology));
        public static readonly AttractionType WildMouse = Register(new AttractionType("WildMouse", RectArea(3, 2), new Rectangle(2, 1, 3, 2), 100, 60000, FastCars));
        public static readonly AttractionType LogFlume = Register(new AttractionType("LogFlume", new[,] {{true, true, false}, {true, true, true}}, new Rectangle(0, 3, 3, 2), 160, 90000, FastCars));
        public static readonly AttractionType HeartlineTwister = Register(new AttractionType("HeartlineTwister", RectArea(4, 2), new Rectangle(5, 4, 4, 2), 250, 150000, FastCars));
        public static readonly AttractionType WoodCoaster = Register(new AttractionType("WoodCoaster", RectArea(3, 3), new Rectangle(0, 5, 3, 3), 300, 215000, FastCars));
        public static readonly AttractionType SafariZone = Register(new AttractionType("SafariZone", RectArea(5, 3), new Rectangle(11, 0, 5, 3), 600, 750000, Relaxed | Walking | NonTechnology));

        public readonly string Name;
        public readonly bool[,] Area;
        public int Width => this.Area.GetLength(1);
        public int Height => this.Area.GetLength(0);
        public readonly Rectangle TextureRegion;
        private readonly float generationPerSecond;
        public readonly long InitialPrice;
        public readonly AttractionFlags Flags;

        public AttractionType(string name, bool[,] area, Rectangle textureRegion, float generationPerSecond, long initialPrice, AttractionFlags flags) {
            this.Name = name;
            this.Area = area;
            this.TextureRegion = textureRegion;
            this.generationPerSecond = generationPerSecond;
            this.InitialPrice = initialPrice;
            this.Flags = flags;
        }

        public Attraction Create() {
            return new Attraction(this);
        }

        public double GetGenerationRate() {
            var genRate = this.generationPerSecond;

            if (this.Flags.HasFlag(FastCars) && Upgrade.RollerCoasterModifier.IsActive())
                genRate *= 2;
            if (this.Flags.HasFlag(Walking) && Upgrade.ManualRideModifier.IsActive())
                genRate *= 3;
            if (this.Flags.HasFlag(NonTechnology) && Upgrade.NatureModifier.IsActive())
                genRate *= 2;

            return genRate;
        }

        public IEnumerable<Point> GetCoveredTiles() {
            for (var x = 0; x < this.Width; x++) {
                for (var y = 0; y < this.Height; y++) {
                    if (this.Area[y, x])
                        yield return new Point(x, y);
                }
            }
        }

        private static AttractionType Register(AttractionType type) {
            Attractions.Add(type.Name, type);
            return type;
        }

        private static bool[,] RectArea(int width, int height) {
            var ret = new bool[height, width];
            for (var x = 0; x < width; x++) {
                for (var y = 0; y < height; y++)
                    ret[y, x] = true;
            }
            return ret;
        }

        public delegate Attraction Constructor(AttractionType type);

        public class Converter : JsonConverter<AttractionType> {

            public override void WriteJson(JsonWriter writer, AttractionType value, JsonSerializer serializer) {
                if (value != null)
                    writer.WriteValue(value.Name);
            }

            public override AttractionType ReadJson(JsonReader reader, Type objectType, AttractionType existingValue, bool hasExistingValue, JsonSerializer serializer) {
                return reader.Value != null ? Attractions[reader.Value.ToString()] : null;
            }

        }

    }
}