using System;
using System.IO;
using UnityEngine;
using System.Collections.Generic;
using IntelligentProjectAnalyzer.Helper;
using static IntelligentProjectAnalyzer.Editor.DependencyBuilderData;

namespace IntelligentProjectAnalyzer.Editor.DependencyViewer
{
    /// <summary>
    /// Loads, parses, and organizes dependency data from the cache into a queryable graph.
    /// This version reads the unified AssetMetadata structure.
    /// </summary>
    public class DependencyGraph
    {
        // Maps an asset's GUID to a list of GUIDs it depends.
        private readonly Dictionary<string, List<string>> _dependencies = new();

        // Maps an asset's GUID to a list of GUIDs that reference it.
        private readonly Dictionary<string, List<string>> _references = new();
        
        private readonly HashSet<string> _allKnownGuids = new();

        /// <summary>
        /// Initializes a new instance of the DependencyGraph class and builds it from the cache.
        /// </summary>
        public DependencyGraph()
        {
            BuildGraph();
        }

        /// <summary>
        /// Gets the list of assets that the specified asset depends on.
        /// </summary>
        public List<string> GetDependencies(string guid)
        {
            return _dependencies.TryGetValue(guid, out var dependencies) ? dependencies : new List<string>();
        }

        /// <summary>
        /// Gets the list of assets that reference the specified asset.
        /// </summary>
        public List<string> GetReferences(string guid)
        {
            return _references.TryGetValue(guid, out var refs) ? refs : new List<string>();
        }
        
        /// <summary>
        /// Checks if the graph contains any data related to the given asset GUID.
        /// </summary>
        public bool AssetExists(string guid)
        {
            return _allKnownGuids.Contains(guid);
        }

        /// <summary>
        /// Clears and rebuilds the entire dependency graph by reading from the cache.
        /// </summary>
        public void BuildGraph()
        {
            _dependencies.Clear();
            _references.Clear();
            _allKnownGuids.Clear();

            var cachePath = DependencyCacheManager.GetCachePath();
            if (!Directory.Exists(cachePath))
            {
                Debug.LogWarning("Cache directory does not exist. Skipping dependency graph build.");
                return;
            }

            var files = Directory.GetFiles(cachePath, "*.json");
            foreach (var file in files)
            {
                try
                {
                    // First, deserialize the outer wrapper object.
                    var wrapper = JsonFileSystem.Read<MetadataWrapper>(file);
                    if (wrapper == null || string.IsNullOrEmpty(wrapper.JsonData))
                    {
                        continue;
                    }

                    // Dynamically get the concrete type from the stored index using our helper.
                    var concreteType = MetadataTypeHelper.GetTypeFromIndex(wrapper.AssetTypeIndex);
                    if (concreteType == null)
                    {
                        Debug.LogWarning($"Could not find a registered type for index '{wrapper.AssetTypeIndex}' during deserialization. Skipping file: {Path.GetFileName(file)}");
                        continue;
                    }

                    // Now, deserialize the nested JSON data into the correct concrete type.
                    var metadata = JsonFileSystem.Read(wrapper.JsonData, concreteType) as AssetMetadata;

                    if (metadata?.DependencyGuids == null) continue;
                    
                    _dependencies[metadata.Guid] = metadata.DependencyGuids;
                    _allKnownGuids.Add(metadata.Guid);
                    foreach(var depGuid in metadata.DependencyGuids)
                    {
                        _allKnownGuids.Add(depGuid);
                    }
                }
                catch (Exception e)
                {
                    Debug.LogError($"Failed to parse dependency file {Path.GetFileName(file)}. Error: {e.Message}");
                }
            }

            // Now, build the inverse map (the references).
            foreach (var (referrerGuid, dependencies) in _dependencies)
            {
                foreach (var dependencyGuid in dependencies)
                {
                    if (!_references.ContainsKey(dependencyGuid))
                    {
                        _references[dependencyGuid] = new List<string>();
                    }
                    _references[dependencyGuid].Add(referrerGuid);
                }
            }
        }
    }
}
