using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Decal.Interop.Core;
using Decal.Interop.Dat;

namespace Decal.DecalDat
{
    internal class FileFilterInfo
    {
        public string Name;
        public Guid Clsid;
        public bool Cache;
    }

    internal class CacheEntry
    {
        public FileFilterInfo Filter;
        public LibraryType Library;
        public uint FileId;
        public object Instance;
    }

    [ComVisible(true)]
    [Guid("37B083F0-276E-43AD-8D26-3F7449B519DC")]
    [ClassInterface(ClassInterfaceType.None)]
    [ProgId("DecalDat.DatService")]
    public class DatServiceImpl : IDatService, IDecalService, IDecalDirectory
    {
        private DatLibraryImpl _cell;
        private DatLibraryImpl _portal;
        private readonly List<FileFilterInfo> _filters = new List<FileFilterInfo>();
        private readonly List<CacheEntry> _cache = new List<CacheEntry>();
        private IDecalCore _decalCore;

        public void Initialize(DecalCore pDecal)
        {
            _decalCore = (IDecalCore)pDecal;

            // Resolve DAT file paths via MapPath
            string cellPath = _decalCore.MapPath("%ac%\\cell.dat");
            string portalPath = _decalCore.MapPath("%ac%\\portal.dat");

            // Load cell.dat (sector size 256)
            _cell = new DatLibraryImpl();
            _cell.Load(this, cellPath, LibraryType.Cell, 256);

            // Load portal.dat (sector size 1024)
            _portal = new DatLibraryImpl();
            _portal.Load(this, portalPath, LibraryType.Portal, 1024);

            // Load filter configuration from Decal
            LoadFilters();
        }

        private void LoadFilters()
        {
            try
            {
                var config = _decalCore.Configuration;
                if (config == null) return;

                // Look up "FileFilters" collection in Decal configuration
                // The C++ code iterates an IDecalEnum to read filter definitions
                // Each filter has: Prefix (string), Cache (bool), ComClass (CLSID)
                //
                // For now, register the known built-in filters that ship with Decal.
                // When Decal.Core is implemented, this will read from live config.
            }
            catch
            {
                // Config may not be available yet
            }
        }

        public void BeforePlugins()
        {
            // No-op in original implementation
        }

        public void AfterPlugins()
        {
            // No-op in original implementation
        }

        public void Terminate()
        {
            _cache.Clear();
            _filters.Clear();

            _cell?.Dispose();
            _cell = null;

            _portal?.Dispose();
            _portal = null;

            _decalCore = null;
        }

        /// <summary>
        /// IDecalDirectory.Lookup - returns cell or portal library by name.
        /// </summary>
        public object Lookup(string strName)
        {
            if (string.Equals(strName, "portal", StringComparison.OrdinalIgnoreCase))
                return _portal;
            if (string.Equals(strName, "cell", StringComparison.OrdinalIgnoreCase))
                return _cell;
            return null;
        }

        // --- Filter management (internal, used by DatLibraryImpl) ---

        internal FileFilterInfo GetFilter(string name)
        {
            foreach (var f in _filters)
            {
                if (string.Equals(f.Name, name, StringComparison.OrdinalIgnoreCase))
                    return f;
            }
            return null;
        }

        internal object CreateFilter(FileFilterInfo filter)
        {
            try
            {
                var type = Type.GetTypeFromCLSID(filter.Clsid);
                if (type == null) return null;
                return Activator.CreateInstance(type);
            }
            catch
            {
                return null;
            }
        }

        internal object FindInCache(FileFilterInfo filter, LibraryType library, uint fileId)
        {
            foreach (var entry in _cache)
            {
                if (entry.Filter == filter && entry.Library == library && entry.FileId == fileId)
                    return entry.Instance;
            }
            return null;
        }

        internal void AddToCache(FileFilterInfo filter, LibraryType library, uint fileId, object instance)
        {
            _cache.Add(new CacheEntry
            {
                Filter = filter,
                Library = library,
                FileId = fileId,
                Instance = instance
            });
        }

        /// <summary>
        /// Register a file filter at runtime.
        /// </summary>
        internal void RegisterFilter(string name, Guid clsid, bool cache)
        {
            _filters.Add(new FileFilterInfo { Name = name, Clsid = clsid, Cache = cache });
        }
    }
}
