using System;
using System.Collections.Generic;
using System.Linq;
using Intrepid.Gameplay.Entities.Player.PDA.Inputs;
using Intrepid.Gameplay.Themes;
using Intrepid.Sound;
using Intrepid.Structures;
using Intrepid.Utilities;
using Sirenix.OdinInspector;
using UnityEngine;

namespace Intrepid.Gameplay.Entities.Player.PDA
{
    [Serializable]
    [CreateAssetMenu(fileName = "PDA Device", menuName = "GON/PDA/PDA Device")]
    public class PDADevice : ScriptableObject
    {
        [GroupConfigurations("Prefabs"), SerializeField] private PDAApplicationLibraryData applicationLibrary;
        
        [GroupConfigurations("Music"), SerializeField] private List<SoundMusicData> musicKnown;
        [GroupConfigurations("Themes"), SerializeField] private List<Theme> themesKnown;
        
        [GroupConfigurations("Apps"), SerializeField] private PDAContentTag overrideApp;
        [GroupConfigurations("Apps"), SerializeField] private List<PDAContentTag> inMemoryApps;
        [GroupConfigurations("Apps"), SerializeField] private List<PDAContentTag> externalApps;

        [GroupDebug, ShowInInspector, ReadOnly] public ParameterStore ParameterStore { get; private set; } = new();
        private List<PDAContentTag> InMemoryApps => inMemoryApps;
        private List<PDAContentTag> ExternalApps => externalApps;
        public PDAContentTag OverrideApp => overrideApp;
        public PDAInputs PDAInputs => PlayerInputResolver.Instance.PDA;
        
        private void OnEnable()
        {
            ExternalApps.Clear();
            ParameterStore.Clear();
        }

        public Func<MonoBehaviour> ApplicationLoader(PDAContentTag contentTag, Transform parent)
        {
            return () => applicationLibrary.Load(contentTag, parent);
        }

        public List<SoundMusicData> GetMusicKnown()
        {
            return musicKnown;
        }
        
        public List<Theme> GetThemesKnown()
        {
            return themesKnown;
        }

        public PDAContentTag GetOverrideContentTag()
        {
            if (OverrideApp.IsNull()) return null;
            return OverrideApp;
        }

        public List<PDAContentTag> GetAvailableContentTags()
        {
            return InMemoryApps.Concat(ExternalApps).ToList();
        }
        
        public void InstallExternalApp(PDAContentTag contentTag, params Parameter[] parameters)
        {
            if (contentTag.IsNull())
            {
                throw new ArgumentException("Content tag cannot be null");
            }
            if (!applicationLibrary.Contains(contentTag))
            {
                throw new ArgumentException($"Content tag {contentTag} not found in library");
            }
            if (parameters is null || parameters.Length != contentTag.Parameters.Count)
            {
                throw new ArgumentException("Invalid number of parameters");
            }
            if (!parameters.Select(p => p.Key).Distinct().All(k => contentTag.Parameters.Contains(k)))
            {
                throw new ArgumentException("parameters should fit the request");
            }
            foreach (var parameter in parameters)
            {
                ParameterStore.Add(parameter);
            }
            ExternalApps.Add(contentTag);
        }

        public void RemoveExternalApp(PDAContentTag contentTag)
        {
            if (contentTag.IsNull()) return;
            if (!applicationLibrary.Contains(contentTag)) return;
            foreach (var key in contentTag.Parameters)
            {
                ParameterStore.Delete(key);
            }
            ExternalApps.Remove(contentTag);
        }
    }
}