using Jovian.EncounterSystem;
using Jovian.ZoneSystem;
using UnityEngine;

namespace Nox.Game {
    public class EncounterHandler {
        private readonly ZoneSystem zoneSystem;
        private readonly EncounterRegistry encounterRegistry;
        private readonly AdventureData adventureData;
        private readonly EncounterView encounterView;
        private string previousZoneId;
        private int previousDay;

        public EncounterHandler(ZoneSystem zoneSystem, EncounterRegistry encounterRegistry, EncounterPrefabs encounterPrefabs, AdventureData adventureData) {
            this.zoneSystem = zoneSystem;
            this.encounterRegistry = encounterRegistry;
            this.adventureData = adventureData;
            encounterView = new EncounterView(encounterPrefabs);
        }

        public bool AskForRandomEncounter(ZoneContext zoneContext, string encounterTableId, out IEncounter encounter) {
            return ResolveEncounter(zoneContext, encounterTableId, out encounter);
        }

        public bool AskForRandomEncounterOfType(ZoneContext zoneContext, string encounterTableId, out IEncounter encounter, IEncounterKind encounterKind) {
            return ResolveEncounter(zoneContext, encounterTableId, out encounter, encounterKind);
        }

        public bool AskForEncounter(string encounterId, out IEncounter encounter) {
            return encounterRegistry.GetEncounters().TryGetValue(encounterId, out encounter);
        }

        private bool ResolveEncounter(ZoneContext zoneContext, string encounterTableId, out IEncounter encounter, IEncounterKind encounterKind = null) {
            encounter = null;
            if(zoneContext.isSafe) {
                return false;
            }

            var randomChance = Random.Range(0f, 1f);
            var shouldTrigger = randomChance <= zoneContext.finalEncounterChance;

            if(!shouldTrigger) {
                return false;
            }

            if(encounterKind == null) {
                encounter = encounterRegistry.GetRandomEncounter(encounterTableId);
                return encounter != null;
            }

            encounter = encounterRegistry.GetRandomEncounter(encounterTableId, encounterKind);
            return encounter != null;
        }

        private void VerifyZones(Vector3 position) {
            var zoneContext = zoneSystem.QueryZone(position);
            if(string.IsNullOrEmpty(zoneContext.resolvedZoneId)) {
                return;
            }
            var currentZoneId = zoneContext.resolvedZoneId;

            if(currentZoneId != previousZoneId) {
                if(!string.IsNullOrEmpty(currentZoneId)) {
                    Debug.Log($"Entered zone: {currentZoneId} (encounter: {zoneContext.encounterTableId}, safe: {zoneContext.isSafe})");
                    if(ResolveEncounter(zoneContext, currentZoneId, out var encounter)) {
                        TriggerEncounter(encounter);
                    }

                }
                else if(!string.IsNullOrEmpty(previousZoneId)) {
                    Debug.Log($"Left zone: {previousZoneId}");
                }
                previousZoneId = currentZoneId;
            }
        }

        private void TriggerEncounter(IEncounter encounter) {
            switch(encounter.EncounterDefinition.Kind) {
                case CombatKind:
                    return;
                default:
                    encounterView?.SetCurrentEncounter(encounter);
                    encounterView?.Show();
                    break;
            }
        }

        public void CheckForEncounters(Vector3 position) {
            if (adventureData.currentDay != previousDay) {
                VerifyZones(position);
            }
        }

        public void Tick() { }

        public void Dispose() {
            // nothing here
        }
    }
}
