using CtrEditor.ObjetosSim;
using LibS7Adv;
using Newtonsoft.Json;
using System.Collections.ObjectModel;
using System.Windows;
using CtrEditor.Simulacion;
using System.IO;
using System.Linq;
using System.Windows.Media;

namespace CtrEditor.Serialization
{
    public class StateSerializer
    {
        private readonly DatosDeTrabajo _datosDeTrabajo;
        private readonly MainViewModel _mainViewModel;
        private readonly SimulationManagerBEPU _simulationManager;

        public StateSerializer(MainViewModel mainViewModel, DatosDeTrabajo datosDeTrabajo, SimulationManagerBEPU simulationManager)
        {
            _mainViewModel = mainViewModel;
            _datosDeTrabajo = datosDeTrabajo;
            _simulationManager = simulationManager;
        }

        public void SaveState(string selectedImage)
        {
            if (selectedImage != null)
            {
                _mainViewModel.StopSimulation();
                _mainViewModel.DisconnectPLC();

                var objetosSimulables = new ObservableCollection<osBase>();
                var objetosSimulablesAllPages = new ObservableCollection<osBase>();
                var datosLocalesObjetos = new ObservableCollection<DatosLocales>();

                // Paso 1: Preparar objetos globales y locales
                foreach (var obj in _mainViewModel.ObjetosSimulables)
                {
                    // Para objetos globales con datos locales
                    if (obj.Enable_On_All_Pages && obj.Enable_Local_Data)
                    {
                        // Guarda los datos locales independientemente de Show_On_This_Page
                        var datosLocales = obj.ObtenerDatosLocales();
                        if (datosLocales != null)
                        {
                            datosLocalesObjetos.Add(datosLocales);
                        }

                        // Restaura datos globales para guardar
                        obj.RestaurarDesdeSnapshotGlobal();
                    }

                    // Prepara para serializaci�n
                    obj.SalvarDatosNoSerializables();

                    // Separa objetos globales y locales
                    if (!obj.Enable_On_All_Pages)
                    {
                        objetosSimulables.Add(obj);
                    }
                    else
                    {
                        objetosSimulablesAllPages.Add(obj);
                    }
                }

                // Paso 2: Capturar estado del workspace antes de guardar
                _mainViewModel.CaptureWorkspaceState();

                // Paso 3: Guardar datos de la página actual
                var dataToSerialize = new SimulationData
                {
                    ObjetosSimulables = objetosSimulables.Count > 0 ? objetosSimulables : null,
                    UnitConverter = PixelToMeter.Instance.calc,
                    PLC_ConnectionData = _mainViewModel.PLCViewModel,
                    WorkspaceConfig = _mainViewModel.WorkspaceConfig,
                    DatosLocalesObjetos = datosLocalesObjetos.Count > 0 ? datosLocalesObjetos : null,
                    ImageDataDictionary = _mainViewModel._imageDataDictionary.Count > 0 ? _mainViewModel._imageDataDictionary : null
                };

                var path = _datosDeTrabajo.ObtenerPathImagenConExtension(selectedImage, ".json");
                if (path != null)
                    SerializeAndSave(dataToSerialize, path);

                // Paso 3: Guardar objetos globales
                path = _datosDeTrabajo.ObtenerPathAllPages(".json");
                if (path != null)
                    SerializeAndSave(objetosSimulablesAllPages, path);

                // Paso 4: Restaurar estado para seguir trabajando
                foreach (var obj in _mainViewModel.ObjetosSimulables)
                {
                    obj.RestaurarDatosNoSerializables();

                    // Para objetos globales, restaura los datos locales
                    if (obj.Enable_On_All_Pages && obj.Enable_Local_Data)
                    {
                        obj.RestaurarDatosLocales();
                    }
                }
            }
        }

        public void LoadState(string selectedImage)
        {
            try
            {
                _mainViewModel.StopSimulation();
                _mainViewModel.DisconnectPLC();
                _mainViewModel.ObjetosSimulables.Clear();
                _simulationManager.Clear();

                if (selectedImage != null)
                {
                    var settings = GetJsonSerializerSettings();

                    // Paso 1: Cargar objetos globales
                    LoadAllPagesState(settings);

                    // Paso 2: Cargar datos de la página actual
                    var simulationData = LoadCurrentPageState(selectedImage, settings);

                    // Paso 2.1: Restaurar configuración del workspace
                    // Usar un dispatcher para asegurar que la UI esté lista
                    System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        _mainViewModel.RestoreWorkspaceState();
                    }), System.Windows.Threading.DispatcherPriority.Background);

                    // Paso 3: Crear snapshots de los objetos globales
                    // Nota: No filtramos por Enable_Local_Data aqu� ya que se establecer� despu�s
                    foreach (var obj in _mainViewModel.ObjetosSimulables)
                    {
                        if (obj.Enable_On_All_Pages)
                        {
                            obj.CrearSnapshotGlobal();
                        }
                    }

                    // Paso 4: Aplicar datos locales a objetos globales
                    if (simulationData?.DatosLocalesObjetos != null)
                    {
                        // Primero, desactivar Enable_Local_Data en todos los objetos globales
                        foreach (var obj in _mainViewModel.ObjetosSimulables.Where(o => o.Enable_On_All_Pages))
                        {
                            obj.Enable_Local_Data = false;
                        }

                        // Luego aplicar los datos locales, esto activar� Enable_Local_Data autom�ticamente
                        foreach (var datosLocales in simulationData.DatosLocalesObjetos)
                        {
                            var objetoGlobal = _mainViewModel.ObjetosSimulables.FirstOrDefault(
                                o => o.Enable_On_All_Pages &&
                                o.Id.Value == datosLocales.Id_GlobalObject.Value);

                            if (objetoGlobal != null)
                            {
                                objetoGlobal.AplicarDatosLocales(datosLocales);
                            }
                        }
                    }

                    // Paso 5: Crear controles visuales
                    foreach (var objetoSimulable in _mainViewModel.ObjetosSimulables)
                    {
                        if (objetoSimulable != null)
                        {
                            objetoSimulable.CheckData();
                            _mainViewModel.CrearUserControlDesdeObjetoSimulable(objetoSimulable);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error loading state: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private SimulationData LoadCurrentPageState(string selectedImage, JsonSerializerSettings settings)
        {
            SimulationData simulationData = null;
            string jsonPath = _datosDeTrabajo.ObtenerPathImagenConExtension(selectedImage, ".json");
            if (File.Exists(jsonPath))
            {
                string jsonString = File.ReadAllText(jsonPath);
                simulationData = JsonConvert.DeserializeObject<SimulationData>(jsonString, settings);
                if (simulationData != null)
                {
                    if (simulationData.ObjetosSimulables is not null)
                    {
                        foreach (var obj in simulationData.ObjetosSimulables)
                            _mainViewModel.ObjetosSimulables.Add(obj);
                    }

                    if (simulationData.PLC_ConnectionData is not null)
                        _mainViewModel.PLCViewModel = simulationData.PLC_ConnectionData;
                    else
                        _mainViewModel.PLCViewModel = new PLCViewModel();

                    // Cargar configuración del workspace
                    if (simulationData.WorkspaceConfig is not null)
                        _mainViewModel.WorkspaceConfig = simulationData.WorkspaceConfig;
                    else
                        _mainViewModel.InitializeDefaultWorkspaceConfig();

                    // Solo sobrescribir el UnitConverter si existe uno guardado
                    if (simulationData.UnitConverter != null)
                        PixelToMeter.Instance.calc = simulationData.UnitConverter;

                    // Cargar datos de imágenes
                    if (simulationData.ImageDataDictionary != null)
                    {
                        _mainViewModel._imageDataDictionary.Clear();
                        foreach (var imageDataEntry in simulationData.ImageDataDictionary)
                        {
                            _mainViewModel._imageDataDictionary[imageDataEntry.Key] = imageDataEntry.Value;
                        }
                    }

                    // Compatibilidad con versiones anteriores (ImageCustomNames)
#pragma warning disable CS0618 // Type or member is obsolete
                    if (simulationData.ImageCustomNames != null)
                    {
                        foreach (var customName in simulationData.ImageCustomNames)
                        {
                            var imageData = _mainViewModel.GetOrCreateImageData(customName.Key);
                            imageData.CustomName = customName.Value;
                        }
                    }
#pragma warning restore CS0618
                }
            }
            return simulationData;
        }

        private void LoadAllPagesState(JsonSerializerSettings settings)
        {
            string jsonPath = _datosDeTrabajo.ObtenerPathAllPages(".json");
            if (File.Exists(jsonPath))
            {
                string jsonString = File.ReadAllText(jsonPath);
                var objetosSimulablesAllPages = JsonConvert.DeserializeObject<ObservableCollection<osBase>>(jsonString, settings);
                if (objetosSimulablesAllPages != null)
                {
                    foreach (var obj in objetosSimulablesAllPages)
                        _mainViewModel.ObjetosSimulables.Add(obj);
                }
            }
        }

        private void SerializeAndSave(object objectToSerialize, string path)
        {
            // Create backup if file exists
            if (File.Exists(path))
            {
                var backupPath = Path.ChangeExtension(path, ".bak");
                File.Copy(path, backupPath, true);
            }

            var settings = GetJsonSerializerSettings();
            var serializedData = JsonConvert.SerializeObject(objectToSerialize, settings);
            File.WriteAllText(path, serializedData);
        }

        private JsonSerializerSettings GetJsonSerializerSettings()
        {
            return new JsonSerializerSettings
            {
                Formatting = Formatting.Indented,
                NullValueHandling = NullValueHandling.Ignore,
                TypeNameHandling = TypeNameHandling.Auto,
                ObjectCreationHandling = ObjectCreationHandling.Replace,
                ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
                Error = HandleDeserializationError,
                Converters = { new SafeImageSourceConverter() },
                // Configuración para respetar atributos JsonIgnore de Newtonsoft.Json
                ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver
                {
                    IgnoreSerializableAttribute = false
                }
            };
        }

        private void HandleDeserializationError(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs e)
        {
            // Si es un error relacionado con ImagePath, ImageSource o osCustomImage, simplemente ignorarlo y continuar
            if (e.ErrorContext.Error.Message.Contains("ImagePath") ||
                e.ErrorContext.Error.Message.Contains("osCustomImage") ||
                e.ErrorContext.Error.Message.Contains("ImageSource") ||
                e.ErrorContext.Error.Message.Contains("lmageSource") || // posible typo en el mensaje de error
                (e.ErrorContext.Path != null && e.ErrorContext.Path.Contains("ImageSource")) ||
                (e.ErrorContext.Path != null && e.ErrorContext.Path.Contains("imagePath")) ||
                (e.ErrorContext.Member != null && e.ErrorContext.Member.ToString().Contains("Image")))
            {
                e.ErrorContext.Handled = true;

                // Si el contexto actual es un objeto osCustomImage y hay un error,
                // intentar establecer valores por defecto
                if (e.ErrorContext.OriginalObject is osCustomImage customImage)
                {
                    try
                    {
                        // Establecer valores seguros por defecto
                        if (e.ErrorContext.Member?.ToString() == "ImagePath" ||
                            e.ErrorContext.Member?.ToString() == "imagePath")
                        {
                            customImage.ImagePath = ""; // Esto activará el fallback a imagen por defecto
                        }
                    }
                    catch
                    {
                        // Si incluso esto falla, simplemente ignorar
                    }
                }
            }
        }
    }

    /// <summary>
    /// Convertidor JSON seguro para ImageSource que nunca lanza excepciones
    /// </summary>
    public class SafeImageSourceConverter : JsonConverter<ImageSource>
    {
        public override ImageSource ReadJson(JsonReader reader, Type objectType, ImageSource existingValue, bool hasExistingValue, JsonSerializer serializer)
        {
            try
            {
                // Si el valor es null o string vacío, devolver null
                if (reader.Value == null || reader.Value.ToString() == "")
                    return null;

                // Intentar crear ImageSource desde el valor
                string value = reader.Value.ToString();

                // Limpiar caracteres problemáticos
                value = value.Trim();
                if (value.Contains("•"))
                    value = value.Replace("•", "");
                if (value.StartsWith("filet///"))
                    value = value.Replace("filet///", "file:///");

                // Si el valor limpio está vacío, devolver null
                if (string.IsNullOrWhiteSpace(value))
                    return null;

                // No intentar crear ImageSource aquí, simplemente devolver null
                // La lógica de carga de imagen se manejará en el código de la aplicación
                return null;
            }
            catch
            {
                // En caso de cualquier error, devolver null silenciosamente
                return null;
            }
        }

        public override void WriteJson(JsonWriter writer, ImageSource value, JsonSerializer serializer)
        {
            // Nunca serializar ImageSource, siempre escribir null
            writer.WriteNull();
        }
    }
}