using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;

public class SaveEquipmentManager : SaveModelSystem<IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAsset>>
{
    public override bool SaveModelItem(IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAsset> model)
    {
        return base.SaveModelItem(model);
    }

    public override bool SaveModelList(List<IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAsset>> list)
    {
        BinaryFormatter formatter = new BinaryFormatter();

        Debug.Log("Saved Equipment at " + Path);

        if (!Directory.Exists(Path)) Directory.CreateDirectory(Path);

        /* Main logic of  conversion data format */
        var data = ConvertObjectsListToListOfDataModels(list);

        FileStream stream = new FileStream(
            Path + GetFileName(ObjectListName),
            FileMode.Create
        );

        formatter.Serialize(stream, data);
        stream.Close();

        return true;
    }

    public override IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAsset> LoadModelItem()
    {
        return base.LoadModelItem();
    }

    public override List<IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAsset>> LoadModelList()
    {
        string path = Path + GetFileName(ObjectListName);

        if (File.Exists(path))
        {
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream stream = new FileStream(path, FileMode.Open);

            List<IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAssetData>> euipmentList = formatter.Deserialize(stream) as List<IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAssetData>>;
            stream.Close();

            return ConvertListOfDataModelsToListOfObject(euipmentList);
        }
        else
        {
            Debug.Log("Save file not found in " + path);
        }

        return new List<IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAsset>>();
    }

    // Support function

    // 1. From model to data format
    private IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAssetData> ConvertObjectToDataModel(IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAsset> model)
    {
        if (model.Value != null)
            return new IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAssetData>(model.Key, new EquippableItemPrefabAssetData(model.Value));
        else
            return new IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAssetData>(model.Key, null);

    }

    private List<IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAssetData>> ConvertObjectsListToListOfDataModels(List<IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAsset>> modelsList)
    {
        // 1. prepare list with all slot possibiliteies
        List<IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAssetData>> convertedList = GetEmptyListOfEquipmentSlotsPrefabData();

        // 2. Assign values
        foreach (IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAsset> model in modelsList)
        {
            convertedList.RemoveAll(slot => slot.Key == model.Key);
            convertedList.Add(ConvertObjectToDataModel(model));
        }

        return convertedList;
    }

    // 2. From data to model format
    private IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAsset> ConvertDataModelToObject(IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAssetData> dataModel)
    {
        if(dataModel.Value != null)
            return new IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAsset>(dataModel.Key, (EquippableItemPrefabAsset)dataModel.Value.MapDataToPrefabAssetModel());
        else
            return new IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAsset>(dataModel.Key, null);
    }

    private List<IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAsset>> ConvertListOfDataModelsToListOfObject(List<IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAssetData>> dataModelsList)
    {
        // 1. prepare list with all slot possibiliteies
        List<IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAsset>> convertedList = GetEmptyListOfEquipmentSlotsPrefab();

        // 2. Assign values
        foreach (IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAssetData> dataModel in dataModelsList)
        {
            convertedList.RemoveAll(slot => slot.Key == (EquipmentPanelSlotsTypeEnum)dataModel.Key);
            convertedList.Add(ConvertDataModelToObject(dataModel));
        }

        return convertedList;
    }


    // Empty list factories functions
    private List<IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAsset>> GetEmptyListOfEquipmentSlotsPrefab()
    { 
        List<IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAsset>> convertedList = new List<IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAsset>>();
        
        foreach (EquipmentPanelSlotsTypeEnum emptyElement in Enum.GetValues(typeof(EquipmentPanelSlotsTypeEnum))) { convertedList.Add(new IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAsset>(emptyElement, null)); }

        return convertedList;
    }

    private List<IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAssetData>> GetEmptyListOfEquipmentSlotsPrefabData()
    {
        List<IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAssetData>> convertedList = new List<IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAssetData>>();

        foreach (EquipmentPanelSlotsTypeEnum emptyElement in Enum.GetValues(typeof(EquipmentPanelSlotsTypeEnum))) { convertedList.Add(new IndexValuePair<EquipmentPanelSlotsTypeEnum, EquippableItemPrefabAssetData>(emptyElement, null)); }

        return convertedList;
    }
}