#pragma warning disable CS0618 // 类型或成员已过时

using AxibugEmuOnline.Client.ClientCore;
using AxibugProtobuf;
using AxiReplay;
using System;
using UnityEngine;
using UnityEngine.UI;

namespace AxibugEmuOnline.Client
{
    /// <summary>
    /// use <see cref="EmuCore{INPUTDATA}"/> instead
    /// </summary>
    [Obsolete("不可直接继承,需要继承EmuCore类型")]
    public abstract class IEmuCore : MonoBehaviour
    {
        /// <summary> 获得模拟器核心中的状态快照对象 </summary>
        public abstract object GetState();
        /// <summary> 获得模拟器核心中的状态快照字节数据 </summary>
        public abstract byte[] GetStateBytes();
        /// <summary> 加载状态快照 </summary>
        /// <param name="state">该对象应该来自核心的<see cref="GetState"/>方法的返回值,或是从<see cref="GetStateBytes"/>返回的byte数组构建</param>
        public abstract void LoadState(object state);
        /// <summary> 加载状态快照 </summary>
        /// <param name="data">该对象应该来自核心的<see cref="GetStateBytes"/>返回的byte数组</param>
        public abstract void LoadStateFromBytes(byte[] data);
        /// <summary> 暂停核心推帧 </summary>
        public abstract void Pause();
        /// <summary> 恢复核心推帧(从Pause状态恢复) </summary>
        public abstract void Resume();
        /// <summary> 启动模拟器逻辑 </summary>
        public abstract MsgBool StartGame(RomFile romFile);
        /// <summary> 释放模拟器核心 </summary>
        public abstract void Dispose();
        /// <summary> 重置核心,通常由模拟器核心提供的功能 </summary>
        public abstract void DoReset();
        /// <summary> 获得模拟器核心的控制器设置器 </summary>
        /// <returns></returns>
        public abstract IControllerSetuper GetControllerSetuper();
        /// <summary> 核心所属平台 </summary>
        public abstract RomPlatformType Platform { get; }
        /// <summary> 获取当前模拟器帧序号,在加载快照和Reset后,应当重置为0 </summary>
        public abstract uint Frame { get; }

        public abstract bool PushEmulatorFrame();
        /// <summary> 模拟器核心推帧结束 </summary>
        public abstract void AfterPushFrame();
        public abstract void GetAudioParams(out int frequency, out int channels);
        public abstract Texture OutputPixel { get; }
        public abstract RawImage DrawCanvas { get; }
    }

    public abstract class EmuCore<INPUTDATA> : IEmuCore
    {
        public sealed override bool PushEmulatorFrame()
        {
            if (SampleInputData(out var inputData))
            {
                return OnPushEmulatorFrame(inputData);
            }

            return false;
        }

        ulong m_lastTestInput;
        protected bool SampleInputData(out INPUTDATA inputData)
        {
            bool result = false;
            inputData = default(INPUTDATA);

            if (InGameUI.Instance.IsNetPlay)
            {
                ReplayStep replayData;
                int frameDiff;
                bool inputDiff;

                if (App.roomMgr.netReplay.TryGetNextFrame((int)Frame, out replayData, out frameDiff, out inputDiff))
                {
                    if (inputDiff)
                    {
                        App.log.Debug($"{DateTime.Now.ToString("hh:mm:ss.fff")} TryGetNextFrame remoteFrame->{App.roomMgr.netReplay.mRemoteFrameIdx} diff->{frameDiff} " +
                            $"frame=>{replayData.FrameStartID} InPut=>{replayData.InPut}");
                    }

                    inputData = ConvertInputDataFromNet(replayData);
                    result = true;
                }
                else
                {
                    result = false;
                }

                var localState = GetLocalInput();
                var rawData = InputDataToNet(localState);
                if (m_lastTestInput != rawData)
                {
                    m_lastTestInput = rawData;
                    App.log.Debug($"{DateTime.Now.ToString("hh:mm:ss.fff")} Input F:{App.roomMgr.netReplay.mCurrClientFrameIdx} | I:{rawData}");
                }
                App.roomMgr.SendRoomSingelPlayerInput(Frame, rawData);
            }
            else//单机模式
            {
                inputData = GetLocalInput();
                result = true;
            }

            return result;
        }

        protected abstract INPUTDATA GetLocalInput();
        protected abstract INPUTDATA ConvertInputDataFromNet(ReplayStep step);
        protected abstract ulong InputDataToNet(INPUTDATA inputData);
        /// <summary> 模拟器核心推帧 </summary>
        protected abstract bool OnPushEmulatorFrame(INPUTDATA InputData);
    }
}
#pragma warning restore CS0618 // 类型或成员已过时