using PetCompanion.Models;
using PetCompanion.Repositories;

namespace PetCompanion.Services
{
    public class PetService
    {
        private readonly PetRepository petRepository;
        private readonly PetClassService petClassService;
        private readonly GameItemService gameItemService;
        private readonly GameItemsRepository gameItemsRepository;
        private readonly PetInventoryService petInventoryService;

        public PetService(
            PetRepository petRepository,
            PetClassService petClassService,
            GameItemService gameItemService,
            GameItemsRepository gameItemsRepository,
            PetInventoryService petInventoryService)
        {
            this.petRepository = petRepository;
            this.petClassService = petClassService;
            this.gameItemService = gameItemService;
            this.gameItemsRepository = gameItemsRepository;
            this.petInventoryService = petInventoryService;
        }

        public IEnumerable<Pet> GetAllPets(Guid userId)
        {
            return petRepository.GetPetsByUserId(userId.ToString());
        }

        public Pet CreatePet(Guid userId, PetCreationRequest petRequest)
        {
            var petId = Guid.NewGuid().ToString();
            var pet = new Pet
            {
                Id = petId,
                UserId = userId.ToString(),
                Name = petRequest.Name,
                Class = petRequest.Class,
                Health = 100,
                MaxHealth = 100,
                Level = 1,
                Experience = 0,
                Stats = PetStats.BuildFromClass(petRequest.Class),
                Resources = new Resources(),
                GatherActionSince = DateTime.UtcNow,
                PetGatherAction = PetActionGather.IDLE,
                IsDead = false
            };

            var createdPet = petRepository.CreatePet(pet);

            var inventory = petInventoryService.CreateInventory(petId).Result;

            return createdPet;
        }

        public Pet UpdatePetAction(string petId, string userId, PetUpdateActionRequest actionRequest)
        {
            var pet = petRepository.GetPetById(petId, userId);
            if (pet == null)
            {
                throw new Exception("Pet not found");
            }

            if (actionRequest.BasicAction.HasValue)
            {
                var currentTime = DateTime.UtcNow;
                if (pet.PetBasicAction != PetBasicAction.UNKNOWN &&
                    currentTime < pet.BasicActionCooldown.ToUniversalTime().AddSeconds(10))
                {
                    throw new Exception("Pet is still on cooldown");
                }

                pet.BasicActionCooldown = DateTime.UtcNow.AddMinutes(GetCooldownForBasicAction(actionRequest.BasicAction.Value));
                pet.PetBasicAction = actionRequest.BasicAction.Value;

                switch (actionRequest.BasicAction.Value)
                {
                    case PetBasicAction.FEED:
                        pet.Resources.Food -= 1;
                        pet.IncrementStrength(1);
                        pet.Health = Math.Min(pet.Health + 5, pet.MaxHealth);
                        break;
                    case PetBasicAction.SLEEP:
                        pet.IncrementIntelligence(1);
                        pet.IncrementStrength(1);
                        pet.Health = Math.Min(pet.Health + 15, pet.MaxHealth);
                        break;
                    case PetBasicAction.PLAY:
                        pet.Resources.Junk -= 1;
                        pet.IncrementCharisma(1);
                        break;
                }

                return petRepository.UpdatePetBasicAction(pet);
            }
            else if (actionRequest.GatherAction.HasValue)
            {
                pet.PetGatherAction = actionRequest.GatherAction.Value;
                pet.GatherActionSince = DateTime.UtcNow;

                return petRepository.UpdatePetGatherAction(pet);
            }

            return pet;
        }

        // returns in minutes
        private int GetCooldownForBasicAction(PetBasicAction value)
        {
            switch (value)
            {
                case PetBasicAction.FEED:
                    return 5;
                case PetBasicAction.PLAY:
                    return 10;
                case PetBasicAction.SLEEP:
                    return 15;
                default:
                    return 0;
            }
        }

        public Resources GetGatheredResources(string petId, string userId)
        {
            var pet = petRepository.GetPetById(petId, userId);

            if (pet == null)
            {
                throw new Exception("Pet not found");
            }

            return petClassService.CalculateGatheredResources(pet.Stats, pet.Level, pet.PetGatherAction, pet.GatherActionSince);
        }

        public Pet UpdatePetResources(string petId, string userId)
        {
            var pet = petRepository.GetPetById(petId, userId);
            if (pet == null)
            {
                throw new Exception("Pet not found");
            }

            var gatheredResources = petClassService.CalculateGatheredResources(pet.Stats, pet.Level, pet.PetGatherAction, pet.GatherActionSince);

            pet.Resources.Wisdom += gatheredResources.Wisdom;
            pet.Resources.Gold += gatheredResources.Gold;
            pet.Resources.Food += gatheredResources.Food;
            pet.Resources.Junk += gatheredResources.Junk;
            pet.GatherActionSince = DateTime.UtcNow;

            return petRepository.UpdatePetResources(pet);
        }

        public Pet UseItem(string petId, string userId, int itemId)
        {
            var pet = petRepository.GetPetById(petId, userId);
            if (pet == null)
                throw new Exception("Pet not found");

            var inventoryItem = pet.Inventory.Items.FirstOrDefault(i => i.GameItemId == itemId);
            if (inventoryItem == null || inventoryItem.Quantity <= 0)
                throw new Exception("Item not found in inventory");

            gameItemService.ApplyItemEffect(pet, inventoryItem.GameItem);

            inventoryItem.Quantity--;
            if (inventoryItem.Quantity <= 0)
                pet.Inventory.Items.Remove(inventoryItem);

            return petRepository.UpdatePet(pet);
        }

        public Pet EquipItem(string petId, string userId, int itemId)
        {
            var pet = petRepository.GetPetById(petId, userId);
            if (pet == null)
                throw new Exception("Pet not found");

            var inventoryItem = pet.Inventory.Items.FirstOrDefault(i => i.GameItemId == itemId);
            if (inventoryItem == null || inventoryItem.Quantity <= 0)
                throw new Exception("Item not found in inventory");

            if (inventoryItem.GameItem.Type != ItemType.Equipment)
                throw new Exception("Item is not equipment");

            // If there's already an item equipped in that slot, unequip it first
            if (pet.EquippedItems.ContainsKey(inventoryItem.GameItem.EquipTarget))
            {
                UnequipItem(pet, inventoryItem.GameItem.EquipTarget);
            }

            // Apply equipment effects
            gameItemService.ApplyItemEffect(pet, inventoryItem.GameItem);

            // Mark item as equipped
            pet.EquippedItems[inventoryItem.GameItem.EquipTarget] = itemId;

            // Remove from inventory
            inventoryItem.Quantity--;
            if (inventoryItem.Quantity <= 0)
                pet.Inventory.Items.Remove(inventoryItem);

            return petRepository.UpdatePet(pet);
        }

        public Pet UnequipItem(string petId, string userId, ItemEquipTarget equipTarget)
        {
            var pet = petRepository.GetPetById(petId, userId);
            if (pet == null)
                throw new Exception("Pet not found");

            UnequipItem(pet, equipTarget);
            return petRepository.UpdatePet(pet);
        }

        private void UnequipItem(Pet pet, ItemEquipTarget equipTarget)
        {
            if (!pet.EquippedItems.ContainsKey(equipTarget))
                return;

            var equippedItemId = pet.EquippedItems[equipTarget];
            var equippedItem = gameItemsRepository.GetById(equippedItemId);

            if (equippedItem != null)
            {
                // Remove equipment effects
                gameItemService.RemoveItemEffect(pet, equippedItem);

                // Add item back to inventory
                var inventoryItem = pet.Inventory.Items.FirstOrDefault(i => i.GameItemId == equippedItemId);
                if (inventoryItem != null)
                    inventoryItem.Quantity++;
                else
                    pet.Inventory.Items.Add(new InventoryItem
                    {
                        GameItemId = equippedItemId,
                        Quantity = 1,
                        GameItem = equippedItem,
                        InventoryId = pet.Id
                    });
            }

            pet.EquippedItems.Remove(equipTarget);
        }

        public Pet GetPet(string petId, string userId)
        {
            var pet = petRepository.GetPetById(petId, userId);
            if (pet == null)
                throw new Exception("Pet not found");
            return pet;
        }

        public Pet DropItem(string petId, string userId, int itemId)
        {
            var pet = GetPet(petId, userId);

            var inventoryItem = pet.Inventory.Items.FirstOrDefault(i => i.GameItemId == itemId);
            if (inventoryItem == null || inventoryItem.Quantity <= 0)
                throw new Exception("Item not found in inventory");

            inventoryItem.Quantity--;
            if (inventoryItem.Quantity <= 0)
                pet.Inventory.Items.Remove(inventoryItem);

            return petRepository.UpdatePet(pet);
        }

        public Pet AddItemToPet(string petId, string userId, int itemId, int quantity)
        {
            var pet = GetPet(petId, userId);
            var gameItem = gameItemsRepository.GetById(itemId);

            if (gameItem == null)
                throw new Exception("Item not found");

            var inventoryItem = pet.Inventory.Items.FirstOrDefault(i => i.GameItemId == itemId);
            if (inventoryItem != null)
            {
                inventoryItem.Quantity += quantity;
            }
            else
            {
                pet.Inventory.Items.Add(new InventoryItem
                {
                    GameItemId = itemId,
                    Quantity = quantity,
                    GameItem = gameItem,
                    InventoryId = pet.Id
                });
            }

            return petRepository.UpdatePet(pet);
        }
    }
}