using AxiReplay;
using MAME.Core;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using AxibugEmuOnline.Client;
using AxibugEmuOnline.Client.ClientCore;
using AxibugProtobuf;
using static AxibugEmuOnline.Client.NesControllerMapper;
using VirtualNes.Core;
using System.Linq;
using AxibugEmuOnline.Client.Event;

public class UMAME : MonoBehaviour, IEmuCore
{
    public static UMAME instance { get; private set; }
    public MAMEEmu emu { get; private set; }
    UniLog mUniLog;
    UniMouse mUniMouse;
    [HideInInspector]
    public UniVideoPlayer mUniVideoPlayer;
    UniSoundPlayer mUniSoundPlayer;
    UniKeyboard mUniKeyboard;
    UniResources mUniResources;

    public Text mFPS;
    private Canvas mCanvas;
    public List<RomInfo> HadGameList = new List<RomInfo>();
    string mChangeRomName = string.Empty;
    public UniTimeSpan mTimeSpan;
    public bool bQuickTestRom = false;
    public string mQuickTestRom = string.Empty;
    public ReplayWriter mReplayWriter;
    public ReplayReader mReplayReader;
    public long currEmuFrame => emu.currEmuFrame;
    public static System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
    public static bool bInGame { get; private set; }
    public static bool bLogicUpdatePause { get; private set; }
    public string EmuDataPath { get { return App.PersistentDataPath(Platform); } }
    public string RomPath => EmuDataPath + "/RemoteRoms/";
    public string SavePath => EmuDataPath + "/sav/";
    public RomPlatformType Platform { get { return mPlatform; } }
    RomPlatformType mPlatform = RomPlatformType.Cps1;
    public uint Frame => (uint)emu.currEmuFrame;
    void Awake()
    {


        //��Ϊ60֡
        Application.targetFrameRate = 60;
        // ǿ�ƺ���
        Screen.orientation = ScreenOrientation.LandscapeLeft;
        instance = this;
        mFPS = GameObject.Find("FPS").GetComponent<Text>();
        mCanvas = GameObject.Find("Canvas").GetComponent<Canvas>();
        mCanvas.worldCamera = Camera.main;
        emu = new MAMEEmu();
        mUniLog = new UniLog();
        mUniMouse = this.gameObject.AddComponent<UniMouse>();
        mUniVideoPlayer = this.gameObject.AddComponent<UniVideoPlayer>();
        mUniSoundPlayer = GameObject.Find("Audio").transform.GetComponent<UniSoundPlayer>();
        mUniKeyboard = this.gameObject.AddComponent<UniKeyboard>();
        mUniResources = new UniResources();
        mChangeRomName = string.Empty;
        mTimeSpan = new UniTimeSpan();
        emu.Init(RomPath, mUniLog, mUniResources, mUniVideoPlayer, mUniSoundPlayer, mUniKeyboard, mUniMouse, mTimeSpan);
    }
    void OnEnable()
    {
    }
    void OnDisable()
    {
        StopGame();
    }
    #region ʵ�ֽӿ�
    public object GetState()
    {
        return SaveState();
    }
    public byte[] GetStateBytes()
    {
        return SaveState();
    }
    public void LoadState(object state)
    {
        LoadState((byte[])state);
    }
    public void LoadStateFromBytes(byte[] data)
    {
        LoadState(data);
    }
    public void Pause()
    {
        bLogicUpdatePause = false;
    }
    public void Resume()
    {
        bLogicUpdatePause = true;
    }
    public MsgBool StartGame(RomFile romFile)
    {
        mPlatform = romFile.Platform;
        mTimeSpan.InitStandTime();
        if (LoadGame(romFile.FileName, false))
            return true;
        else
            return "Rom����ʧ��";
    }
    public void Dispose()
    {
        StopGame();
    }
    public void DoReset()
    {
        StopGame();
        LoadGame(mChangeRomName, false);
    }
    public IControllerSetuper GetControllerSetuper()
    {
        return mUniKeyboard.ControllerMapper;
    }
    #endregion
    bool LoadGame(string loadRom, bool bReplay = false)
    {
        //Application.targetFrameRate = 60;
        mReplayWriter = new ReplayWriter(mChangeRomName, "fuck", ReplayData.ReplayFormat.FM32IP64, Encoding.UTF8);
        mChangeRomName = loadRom;
        StopGame();
        //��ȡROM
        emu.LoadRom(mChangeRomName);
        //��ȡ�ɹ�
        if (emu.bRom)
        {
            if (bReplay)
            {
                string Path = SavePath + Machine.sName + ".rp";
                mReplayReader = new ReplayReader(Path);
                mUniKeyboard.SetRePlay(true);
            }

            //��ȡROM֮���ÿ��߳�ʼ������
            int _width; int _height; IntPtr _framePtr;
            emu.GetGameScreenSize(out _width, out _height, out _framePtr);
            App.log.Debug($"_width->{_width}, _height->{_height}, _framePtr->{_framePtr}");
            mUniVideoPlayer.Initialize(_width, _height, _framePtr);
            //��ʼ����Ƶ
            mUniSoundPlayer.Initialize();
            //��ʼ��Ϸ
            emu.StartGame();
            bInGame = true;
            bLogicUpdatePause = true;
            return true;
        }
        else
        {
            App.log.Debug($"ROM����ʧ��");
            return false;
        }
    }
    void Update()
    {
        mFPS.text = ($"fpsv {mUniVideoPlayer.videoFPS.ToString("F2")} fpsa {mUniSoundPlayer.audioFPS.ToString("F2")}");

        if (!bInGame)
            return;

        if (bLogicUpdatePause)
        {
            //�ɼ���֡Input
            mUniKeyboard.UpdateInputKey();
            //������һ֡
            //emu.UnlockNextFreme();
            //��֡
            emu.UpdateFrame();
        }

        mUniVideoPlayer.ApplyFilterEffect();
        mUniVideoPlayer.ApplyScreenScaler();
    }
    public void SaveReplay()
    {
        string Path = SavePath + Machine.sName + ".rp";
        string dbgPath = SavePath + Machine.sName + ".rpwrite";
        mReplayWriter.SaveData(Path, true, dbgPath);
    }
    public void StopGame()
    {
        if (bInGame)
        {
            emu.StopGame();
            mUniVideoPlayer.StopVideo();
            mUniSoundPlayer.StopPlay();
            bInGame = false;
            bLogicUpdatePause = false;
        }
    }
    byte[] SaveState()
    {
        if (!Directory.Exists(SavePath))
            Directory.CreateDirectory(SavePath);

        MemoryStream ms = new MemoryStream();
        BinaryWriter bw = new BinaryWriter(ms);
        emu.SaveState(bw);
        byte[] data = ms.ToArray();
        bw.Close();
        ms.Close();

        return data;


        //byte[] screenData = UMAME.instance.mUniVideoPlayer.GetScreenImg();

        //FileStream fsImg = new FileStream(SavePath + Machine.sName + ".jpg", FileMode.Create);
        //fsImg.Write(screenData, 0, screenData.Length);
        //fsImg.Close();
    }
    void LoadState(byte[] data)
    {
        MemoryStream fs = new MemoryStream(data);
        BinaryReader br = new BinaryReader(fs);
        emu.LoadState(br);
        br.Close();
        fs.Close();
    }
}