using System;
using System.Collections;
using System.IO;
using uGIF;
using UnityEngine;
using UnityEngine.UI;
using Image = uGIF.Image;

public class Screenshot : MonoBehaviour
{
    public static Screenshot Instance;
    bool recording = false;

    public Button RecordButton;
    public TMPro.TMP_InputField 
        ScreenshotWidth,
        ScreenshotHeight,
        GifWidth,
        GifHeight;
    public TMPro.TMP_Dropdown CaptureAntialiasing;
    public Toggle CaptureTransparent;

    private void Awake()
    {
        Instance = this;
    }

    public void TakeScreenshot()
    {
        var camera = ModelViewerMain.GetInstance().GetCamera().Cam;
        int width = string.IsNullOrEmpty(ScreenshotWidth.text)? 0 : int.Parse(ScreenshotWidth.text);
        int height = string.IsNullOrEmpty(ScreenshotHeight.text) ? 0 : int.Parse(ScreenshotHeight.text);
        width = width == 0 ? Screen.width : width;
        height = height == 0 ? Screen.height : height;
        var image = GrabFrame(camera, width, height, CaptureTransparent.isOn, GetAntialiasing());

        string fileName = Application.dataPath + "/../Screenshots/" + string.Format("UniViewer_{0}", DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss-fff"));
        byte[] pngShot = ImageConversion.EncodeToPNG(image);
        Directory.CreateDirectory(Application.dataPath + "/../Screenshots");
        var fullpath = Path.GetFullPath($"{fileName}.png");
        File.WriteAllBytes(fullpath, pngShot);
        Error.Log($"Screenshot saved: {fullpath}", Color.green);
        Destroy(image);
    }

    public void BeginRecordGif()
    {
        if (recording || ModelViewerMain.GetInstance().SelectedObject == null)
        {
            Error.Log(Color.yellow, "Target not found");
            return;
        }
        recording = true;
        RecordButton.interactable = false;
        int width = string.IsNullOrEmpty(GifWidth.text) ? 0 : int.Parse(GifWidth.text);
        int height = string.IsNullOrEmpty(GifHeight.text) ? 0 : int.Parse(GifHeight.text);
        ModelViewerMain.GetInstance().StartCoroutine(RecordGif(width, height, CaptureTransparent.isOn, GetAntialiasing())); //(int)UmaViewerUI.Instance.GifQuality.value));
    }


    private IEnumerator RecordGif(int width, int height, bool transparent, int antialiasing)
    {
        var camera = ModelViewerMain.GetInstance().GetCamera().Cam;

        var currentCharacter = ModelViewerMain.GetInstance().SelectedObject;

        if (currentCharacter as IAnimated == null) yield break;

        var animator = (currentCharacter as IAnimated).GetAnimator();

        if (animator == null) yield break;

        int frame = 0;
        var animeClip = (animator.runtimeAnimatorController as AnimatorOverrideController)["Anim"];
        var clipFrameCount = Mathf.RoundToInt(animeClip.length * animeClip.frameRate);
        ModelViewerMain.GetInstance().StartCoroutine(CaptureToGIFCustom.Instance.Encode(animeClip.frameRate, 10));

        animator.speed = 0;
        while (frame < clipFrameCount)
        {
            animator.Play("Anim", 0, (float)frame / clipFrameCount);
            yield return new WaitForEndOfFrame();
            var tex = GrabFrame(camera, width, height, transparent, antialiasing, transparent);
            CaptureToGIFCustom.Instance.Frames.Add(new Image(tex));
            Destroy(tex);
            frame++;
        }

        recording = false;
        CaptureToGIFCustom.Instance.stop = true;
        RecordButton.interactable = true;
    }

    public static Texture2D GrabFrame(Camera cam, int width, int height, bool transparent = true, int antialiasing = 2, bool gifBackground = false)
    {
        var dimensions = GetResolution(width, height);
        width = dimensions.x;
        height = dimensions.y;

        int oldMask = cam.cullingMask;
        var oldClearFlags = cam.clearFlags;
        Color oldBG = cam.backgroundColor;

        cam.cullingMask = ~LayerMask.GetMask("UI");
        if (gifBackground || transparent)
        {
            cam.clearFlags = CameraClearFlags.SolidColor;
            cam.backgroundColor = new Color32(0, 0, 0, 0);
        }

        var tex_color = new Texture2D(width, height, TextureFormat.ARGB32, false);
        var render_texture = RenderTexture.GetTemporary(width, height, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default, antialiasing);
        var grab_area = new Rect(0, 0, width, height);

        RenderTexture.active = render_texture;
        cam.targetTexture = render_texture;

        cam.Render();
        tex_color.ReadPixels(grab_area, 0, 0);
        tex_color.Apply();

        cam.clearFlags = oldClearFlags;
        cam.cullingMask = oldMask;
        cam.backgroundColor = oldBG;
        cam.targetTexture = null;
        RenderTexture.active = null;
        RenderTexture.ReleaseTemporary(render_texture);

        return tex_color;
    }

    public static Vector2Int GetResolution(int width, int height)
    {
        if (width == 0 && height == 0)
        {
            width = Screen.width;
            height = Screen.height;
        }
        else if (width == 0)
        {
            float ratio = (float)Screen.width / (float)Screen.height;
            width = Mathf.RoundToInt((float)height * ratio);
        }
        else if (height == 0)
        {
            float ratio = (float)Screen.height / (float)Screen.width;
            height = Mathf.RoundToInt((float)width * ratio);
        }
        return new Vector2Int(width, height);
    }

    private int GetAntialiasing()
    {
        return int.Parse(CaptureAntialiasing.options[CaptureAntialiasing.value].text);
    }
}