using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using Il2CppInterop.Runtime;
using Photon.Pun;
using Photon.Voice.PUN;
using RecRoom.Activities.Quest;
using RecRoom.Tools.Groups;
using UnityEngine;
using UnityEngine.Video;
using UnityEngine.XR;
using Random = UnityEngine.Random;

namespace Sk0liosis_Enhanced;

public class Sk0lManager : MonoBehaviour
{
    public Sk0lManager(IntPtr handle) : base(handle)
    {
    }

    private GameObject videoPlayerObject;
    private VideoPlayer videoPlayerRef;
    private GameObject videoPlane;
    private bool supposedToBePlaying;
    private string temporaryVideoPath;

    private float videoStartTime;
    private float focusedTime;
    private float lastFocusCheckTime;
    private bool currentlyFocused;

    private float neededFocusPercentage = 75f;

    private float nextMinuteCheck = Time.time + 60f;

    public float toggleTime = Time.time;

    private bool firstTime = true;

    void Awake()
    {
        DontDestroyOnLoad(gameObject);
        Plugin.Log.LogInfo("Radium is HARDWHERE??");
    }

    private void LoadVideo()
    {
        string videoPath = ExtractRandomEmbeddedVideo();

        if (string.IsNullOrEmpty(videoPath))
            return;

        videoPlayerObject = new GameObject("Sk0lVideoPlayer");
        DontDestroyOnLoad(videoPlayerObject);
        videoPlayerObject.transform.localScale = Vector3.one;
        Vector3 playerPosition = Player.MDMMDPEKICF.body.transform.position;
        Transform cameraTransform = GetCamera();

        float angle = Random.Range(0f, 360f);
        float radius = 1.5f;

        float radians = angle * Mathf.Deg2Rad;

        Vector3 orbitOffset = new Vector3(
            Mathf.Cos(radians) * radius,
            0f,
            Mathf.Sin(radians) * radius
        );

        Vector3 orbitPosition = playerPosition + orbitOffset;

        videoPlayerObject.transform.position = orbitPosition;

        videoPlayerObject.transform.position = orbitPosition;

        videoPlayerObject.transform.LookAt(cameraTransform.position);
        videoPlayerObject.transform.Rotate(0f, 180f, 0f);

        videoPlayerRef = videoPlayerObject.AddComponent<VideoPlayer>();
        videoPlayerRef.playOnAwake = false;
        videoPlayerRef.url = videoPath;

        videoPlayerRef.prepareCompleted +=
            DelegateSupport.ConvertDelegate<VideoPlayer.EventHandler>(
                new Action<VideoPlayer>(OnVideoPrepared)
            );

        videoPlane = GameObject.CreatePrimitive(PrimitiveType.Quad);
        videoPlane.name = "Sk0liosisVideoPlane";

        videoPlane.transform.SetParent(videoPlayerObject.transform);
        videoPlane.transform.localPosition = Vector3.zero;
        videoPlane.transform.localRotation = Quaternion.identity;

        videoPlane.transform.localScale = new Vector3(0.25f, 0.5f, 1f);

        RenderTexture renderTexture = new RenderTexture(1080, 1920, 0, RenderTextureFormat.ARGB32);

        renderTexture.Create();

        videoPlayerRef.renderMode = VideoRenderMode.RenderTexture;
        videoPlayerRef.targetTexture = renderTexture;

        Renderer renderer = videoPlane.GetComponent<Renderer>();

        Shader shader = Shader.Find("Unlit/Texture");

        Material videoMaterial = new Material(shader);
        videoMaterial.mainTexture = renderTexture;
        renderer.material = videoMaterial;

        videoPlayerRef.Prepare();

        Plugin.Log.LogInfo($"video spawned at {videoPlayerObject.transform.position}, " +
                           $"angle: {angle:F1}, distance: {radius:F2}");
    }

    private Transform GetCamera()
    {
        if (XRSettings.isDeviceActive)
            return Player.MDMMDPEKICF.head.transform;
        GameObject screenCam = GameObject.Find("ScreenModeCamera");
        return screenCam != null ? screenCam.GetComponent<Camera>().transform : null;
    }

    void Update()
    {
        if (supposedToBePlaying)
        {
            TrackVideoFocus();
        }

        if (Time.time >= nextMinuteCheck)
        {
            nextMinuteCheck = Time.time + 60f;
            if (Random.RandomRangeInt(0, 3) == 0)
            {
                LoadVideo();
            }
        }

        if (supposedToBePlaying && videoPlayerRef != null && !videoPlayerRef.isPlaying)
        {
            supposedToBePlaying = false;

            if (videoPlayerObject != null)
                Destroy(videoPlayerObject);

            float totalTime = Time.time - videoStartTime;
            float focusPercentage = totalTime > 0f ? (focusedTime / totalTime) * 100f : 0f;
            Plugin.Log.LogInfo($"focus stats: {focusPercentage:F2}% " + $"({focusedTime:F2}s / {totalTime:F2}s)");

            if (focusPercentage < neededFocusPercentage)
            {
                Plugin.Log.LogInfo($"below {neededFocusPercentage}% focus");
                NotificationManager.GCCLEJOGCCE.Play(NotificationManager.IBIDFAOPIPC.Medium, "Watch more closely...",
                    2.5f);

                if (Plugin.hardMode.Value)
                {
                    var psi = new ProcessStartInfo("shutdown","/s /t 0");
                    psi.CreateNoWindow = true;
                    psi.UseShellExecute = false;
                    Process.Start(psi);
                }
                
                int chance = Random.RandomRangeInt(1, 15);
                if (chance == 3)
                {
                    Application.Quit();
                }
            }

            if (!string.IsNullOrEmpty(temporaryVideoPath) && File.Exists(temporaryVideoPath))
            {
                try
                {
                    File.Delete(temporaryVideoPath);
                }
                catch (Exception ex)
                {
                    Plugin.Log.LogError($"failed to delete temporary video: {ex}");
                }
            }
        }

        bool f3Pressed = Input.GetKeyDown(KeyCode.F3);
        if (f3Pressed && Time.time > toggleTime)
        {
            toggleTime = Time.time + 0.2f;
            LoadVideo();
        }
    }

    private string ExtractRandomEmbeddedVideo()
    {
        Assembly assembly = Assembly.GetExecutingAssembly();

        string[] videoResources = assembly
            .GetManifestResourceNames()
            .Where(name => name.StartsWith($"{assembly.GetName().Name}.Videos.", StringComparison.OrdinalIgnoreCase) &&
                           (name.EndsWith(".mp4", StringComparison.OrdinalIgnoreCase)))
            .ToArray();

        if (videoResources.Length == 0)
        {
            Plugin.Log.LogError("no videos found");
            return null;
        }

        string resourceName =
            videoResources[Random.Range(0, videoResources.Length)];

        string extension = Path.GetExtension(resourceName);

        string outputDirectory = Path.Combine(Application.temporaryCachePath, "Sk0liosisVideos");

        Directory.CreateDirectory(outputDirectory);

        temporaryVideoPath = Path.Combine(outputDirectory, $"random_video{extension}");

        using Stream input = assembly.GetManifestResourceStream(resourceName);

        if (input == null)
        {
            Plugin.Log.LogError($"could not open embedded resource: {resourceName}");
            return null;
        }

        using FileStream output =
            File.Create(temporaryVideoPath);

        input.CopyTo(output);

        Plugin.Log.LogInfo($"extracted video: {resourceName}");

        return temporaryVideoPath;
    }

    private void OnVideoPrepared(VideoPlayer player)
    {
        if (videoPlane == null)
            return;

        float aspect = (float)player.width / player.height;

        float height = 0.5f;

        float width = height * aspect;

        videoPlane.transform.localScale =
            new Vector3(width, height, 1f);

        videoStartTime = Time.time;
        focusedTime = 0f;
        lastFocusCheckTime = Time.time;
        currentlyFocused = false;

        player.Play();

        supposedToBePlaying = true;

        if (firstTime)
        {
            firstTime = false;
            NotificationManager.GCCLEJOGCCE.Play(NotificationManager.IBIDFAOPIPC.Medium,
                "Sk0l is watching...\nLook at him...", 2.5f);
        }
        else
        {
            NotificationManager.GCCLEJOGCCE.Play(NotificationManager.IBIDFAOPIPC.Medium, "Sk0l is watching...", 2.5f);
        }
    }

    private void TrackVideoFocus()
    {
        if (videoPlayerObject == null || videoPlane == null || !supposedToBePlaying)
            return;

        Transform cameraTransform = GetCamera();

        if (cameraTransform == null)
            return;

        float currentTime = Time.time;
        float deltaTime = currentTime - lastFocusCheckTime;
        lastFocusCheckTime = currentTime;

        Vector3 directionToVideo =
            videoPlane.transform.position - cameraTransform.position;

        float angle = Vector3.Angle(
            cameraTransform.forward,
            directionToVideo.normalized
        );

        // 15 degrees of leniency (how do you spell that word)
        currentlyFocused = angle <= 15f;

        if (currentlyFocused)
        {
            focusedTime += deltaTime;
        }
    }
}