using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.Events;

public class ModelViewerMain : MonoBehaviour
{
    protected static ModelViewerMain _mainInstance;

    [SerializeField]
    public CameraContainer
        MainCameraOrbit,
        WorkCameraOrbit;

    public OperationMode Mode;
    public SceneContainer CurrentScene;
    public ObjectContainer SelectedObject;
    public List<ObjectContainer> SelectedObjects = new List<ObjectContainer>();
    public static UnityEvent<ObjectContainer> OnObjectDeleteEvent = new UnityEvent<ObjectContainer>();

    protected float[] _backupTimes = new float[] { 15 * 60, 5 * 60, 60 };
    protected float[] _backupTimers;

    public enum OperationMode
    {
        Single,
        Multiple
    }

    public static ModelViewerMain GetInstance()
    {
        return _mainInstance;
    }

    public static T GetInstance<T>() where T : ModelViewerMain
    {
        return _mainInstance as T;
    }

    protected virtual void Awake()
    {
        ModelViewerSettings.Load();

        _backupTimers = _backupTimes.ToArray();

        if(CurrentScene == null)
        {
            Debug.LogError("Custom model viewer should create a new scene in Awake()");
            CurrentScene = SceneContainer.Create<SceneContainer>(this);
        }

        if (!MainCameraOrbit.Frames.Any())
            MainCameraOrbit.SetDefaultFrame();

        _mainInstance = this;
    }

    public CameraOrbit GetCamera()
    {
        return CurrentScene.MainCameraOrbit.Camera;
    }

    public CameraContainer GetCameraHandler()
    {
        if (!CurrentScene.MainCameraOrbit.LineRenderer.enabled)
            return CurrentScene.MainCameraOrbit;
        else
            return CurrentScene.WorkCameraOrbit;
    }

    public static void RegisterObject(ObjectContainer container)
    {
        GetInstance().CurrentScene.AllObjects.Add(container);
    }

    public static void UnregisterObject(ObjectContainer container)
    {
        GetInstance().CurrentScene.AllObjects.Remove(container);
        GetInstance().SelectionRemove(container);
    }

    public T GetSelectedObject<T>() where T: ObjectContainer
    {
        return SelectedObject as T;
    }

    public T GetCurrentScene<T>() where T : SceneContainer
    {
        return CurrentScene as T;
    }

    public void SelectObject(ObjectContainer container)
    {
        if (SelectedObject == container) return;

        SelectedObject?.Deselect();
        SelectedObject = container;
        SelectedObject?.Select();

        TimelineController.UpdateTimeline();
    }

    public void PrepareForLoad()
    {
        if (Mode == OperationMode.Single)
        {
            EmptyScene<SceneContainer>();
        }
    }

    public void SelectionAdd(ObjectContainer container)
    {
        if (container == null) return;

        if (SelectedObjects.Count == 0)
        {
            SelectedObjects.Add(container);
            SelectObject(container);
        }
        else if(container != null && !SelectedObjects.Contains(container))
        {
            SelectedObjects.Add(container);
        }
    }

    public void SelectionRemove(ObjectContainer container)
    {
        if (container == null) return;

        bool wasSelected = container == SelectedObject;

        if (container != null && SelectedObjects.Contains(container))
        {
            SelectedObjects.Remove(container);
            if (wasSelected)
            {
                if(SelectedObjects.Count > 0)
                {
                    SelectObject(SelectedObjects[0]);
                }
                else
                {
                    SelectObject(null);
                }
            }
        }
    }

    public virtual void SelectionClear()
    {
        SelectedObjects.Clear();
    }

    public void EmptyScene<T>() where T : SceneContainer
    {
        CurrentScene.Destroy();
        CurrentScene = SceneContainer.Create<T>(this);

        ModelViewerMain.GetInstance().SelectionClear();
        TimelineController.UpdateTimeline();
    }

    public SceneSerializable SaveScene()
    {
        return CurrentScene.Serialize() as SceneSerializable;
    }

    public virtual IEnumerator LoadScene(SceneSerializable bc)
    {
        throw new NotImplementedException();
    }

    protected void AutoSaveUpdate()
    {
        bool skip = false;
        for (int i = 0; i < _backupTimes.Length; i++)
        {
            _backupTimers[i] -= Time.deltaTime;
            if (skip)
            {
                _backupTimers[i] = _backupTimes[i];
            }
            else if (_backupTimers[i] <= 0)
            {
                _backupTimers[i] = _backupTimes[i];

                var scene = SaveScene();
                scene.Filename = $"AutoBackup_{_backupTimes[i]}";
                UISceneContainer.CreateNew(scene, true).Save(true);

                skip = true;
            }
        }
    }
}