using System.Collections.Generic;

namespace SoMRandomizer.processing.openworld.randomization
{
    /// <summary>
    /// A location at which open world "checks" can occur.
    /// </summary>
    /// 
    /// <remarks>Author: Moppleton</remarks>
    public class PrizeLocation
    {
        /// <summary>
        /// Identifier of the location. In each rolled game there are no duplicates.
        /// </summary>
        public readonly LocationId locationId;
        // name of the location - these are unique
        public string locationName;
        // map number
        public int mapNum;
        // npc object number on map; -1 for none
        public int objNum;
        // event parts to replace with item we're giving
        public int eventNum;
        public int eventReplacementIndex;
        // empty if no restrictions
        public string[] prizeTypeOptions;

        public string[] locationHints;

        public string[] lockedByPrizes;
        // higher is easy to get
        public double reachability = 0;

        public PrizeLocation(LocationId id, int map, int obj, int evNum, int evReplaceIndex, string[] typeOptions, string[] hints, string[] lockedBy, double locationReachability)
        {
            // chest constructor, with event replacement for object to ensure it disappears
            locationId = id;
            locationName = IdMap.LocationNames[id];
            mapNum = map;
            objNum = obj;
            eventNum = evNum;
            eventReplacementIndex = evReplaceIndex;
            prizeTypeOptions = typeOptions;
            locationHints = hints;
            lockedByPrizes = lockedBy;
            reachability = locationReachability;
        }

        public PrizeLocation(LocationId id, int evNum, int evReplaceIndex, string[] typeOptions, string[] hints, string[] lockedBy, double locationReachability) : this(id, -1, -1, evNum, evReplaceIndex, typeOptions, hints, lockedBy, locationReachability)
        {
            // non-chest constructor
        }

        public PrizeLocation(LocationId id, int evNum, int evReplaceIndex, string[] typeOptions, string[] lockedBy, double locationReachability) : this(id, evNum, evReplaceIndex, typeOptions, new string[] { }, lockedBy, locationReachability)
        {
            // no hints constructor for starting stuff
        }

        public void updateLockedByPrizes(bool flammieDrumInLogic, string _upperLandElement, string goal)
        {
            if (flammieDrumInLogic)
            {
                List<string> allPrizes = new List<string>();
                allPrizes.AddRange(lockedByPrizes);
                if (OpenWorldPrizes.flammieRequiredLocations.Contains(locationName))
                {
                    // TODO: FIXME: this actually only spells if flammie drum is locked by it
                    allPrizes.Add("flammie drum");
                    if (_upperLandElement != "no" && !allPrizes.Contains(_upperLandElement + " spells"))
                    {
                        allPrizes.Add(_upperLandElement + " spells");
                    }
                }
                else
                {
                    if (goal == OpenWorldGoalProcessor.GOAL_GIFTMODE || goal == OpenWorldGoalProcessor.GOAL_REINDEER)
                    {
                        // reverse logic since we start in ice country
                        if (!OpenWorldPrizes.upperLandOrbRequiredLocations.Contains(locationName))
                        {
                            // TODO: FIXME: this actually needs flammie drum OR spells
                            if (_upperLandElement != "no" && !allPrizes.Contains(_upperLandElement + " spells"))
                            {
                                allPrizes.Add(_upperLandElement + " spells");
                            }
                        }
                    }
                    else
                    {
                        if (OpenWorldPrizes.upperLandOrbRequiredLocations.Contains(locationName))
                        {
                            // TODO: FIXME: this actually needs flammie drum OR spells
                            if (_upperLandElement != "no" && !allPrizes.Contains(_upperLandElement + " spells"))
                            {
                                allPrizes.Add(_upperLandElement + " spells");
                            }
                        }
                    }
                }
                lockedByPrizes = allPrizes.ToArray();
            }
        }

        public string[] getLockedByPrizes(bool flammieDrumInLogic, string _upperLandElement, string goal)
        {
            // TODO: FIXME: we probably don't even need to clone here
            return lockedByPrizes.Clone() as string[];
        }

        public override bool Equals(object obj)
        {
            return obj is PrizeLocation && locationId == ((PrizeLocation)obj).locationId;
        }

        public override int GetHashCode()
        {
            // assume unique names
            return locationName.GetHashCode();
        }
    }
}
