using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Valve.VR;
using System;

[RequireComponent(typeof(AudioSource))]
public class PlayEngine : SingletonBehaviour<PlayEngine>
{
    public LevelListscriptableObject levelList;
    public ForwardNoteObject ForwardNoteObject;
    public EdgeNoteObject[] EdgeNoteObjects = new EdgeNoteObject[4];
    private double startTime;
    
    private Level level;

    private AudioSource audioSource;
    private AudioClip audioClip;

    private bool isPlaying;
    private double startDspTime;

    public int test;

    public List<GameObject> hitEffectPrefabs = new List<GameObject>();

    public AudioClip gunSfx;

    public GameObject explosion;

    public SteamVR_Action_Boolean fire;
    public SteamVR_Input_Sources leftHand;
    public SteamVR_Input_Sources rightHand;

    public GameObject player;

    private int combo;
    private int score;

    public void Start()
    {
        audioSource = GetComponent<AudioSource>();
        LoadAndPlay(0);
    }

    public void LoadAndPlay(int idx)
    {
        var levelData = levelList.levels[idx];
        var bmsText = levelData.bms.text;
        var audioFile = levelData.audioFile;
        var offsetBarTime = levelData.offsetBarTime;

        var bms = new BmsParser().Parse(bmsText);
        var level = bms.ToLevel();

        this.level = level;

        var dspTime = AudioSettings.dspTime;
        var scheduleOffset = 0.5; // scheduling offset
        var playOffset = scheduleOffset + offsetBarTime * (60.0 / level.bpm) * 4; // includes offset bar time

        startDspTime = scheduleOffset + dspTime;

        audioSource.clip = audioFile;
        audioSource.PlayScheduled(playOffset + dspTime);
        Debug.Log(playOffset);
    }

    void OnEnable()
    {
    }

    private void Update()
    {
        if (level != null)
        {
            var playbackTime = AudioSettings.dspTime - startDspTime;
            PlayerInput input = new PlayerInput();
            input.time = playbackTime;

            //get laser
            var handObjects = player.GetComponent<Valve.VR.InteractionSystem.Player>().hands;

            var leftHandObject = handObjects[0];
            var rightHandObject = handObjects[1];

            var leftLaser = leftHandObject.gameObject.GetComponentInChildren<LineRenderer>();
            var rightLaser = rightHandObject.gameObject.GetComponentInChildren<LineRenderer>();
            if(leftLaser)
                    {
                var p1 = leftLaser.transform.TransformPoint(leftLaser.GetPosition(0));
                var p2 = leftLaser.transform.TransformPoint(leftLaser.GetPosition(1));

                input.ray = new Ray(p1, p2-p1);

                Debug.DrawRay(input.ray.origin, input.ray.direction, Color.red);
            }
            level.UpdateNotes(playbackTime);

            if (Input.GetKeyDown(KeyCode.Alpha1))
            {
                input.ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                input.hand = HandType.Left;
                level.HandleInput(input);
            }

            if (Input.GetKeyDown(KeyCode.Alpha2))
            {
                input.ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                input.hand = HandType.Right;
                level.HandleInput(input);
            }

            try // when no VR device is available, SteamVR causes an error.
            {
                // TODO: handle vr input

                if (fire.GetStateDown(leftHand))
                {
                    input.hand = HandType.Left;

                    if (leftLaser)
                    {
                        var p1 = leftLaser.transform.TransformPoint(leftLaser.GetPosition(0));
                        var p2 = leftLaser.transform.TransformPoint(leftLaser.GetPosition(1));

                        input.ray = new Ray(p1, p2-p1);

                        Debug.DrawRay(input.ray.origin, input.ray.direction, Color.magenta, 1);
                        level.HandleInput(input);
                    }
                }
                if (fire.GetStateDown(rightHand))
                {
                    input.hand = HandType.Right;
                    if (rightLaser)
                    {
                        var p1 = rightLaser.transform.TransformPoint(rightLaser.GetPosition(0));
                        var p2 = rightLaser.transform.TransformPoint(rightLaser.GetPosition(1));

                        input.ray = new Ray(p1, p2 - p1);

                        Debug.DrawRay(input.ray.origin, input.ray.direction, Color.cyan, 1);
                        level.HandleInput(input);
                    }
                }
            }
            catch (NullReferenceException e)
            {
                if (e.Source != "SteamVR") // ignore SteamVR, rethrow otherwise
                {
                    throw e;
                }
            }
        }

        if (Input.GetKeyDown(KeyCode.LeftArrow))
        {
            audioSource.time -= 1.0f;
            startDspTime += 1.0f;
        }

        if (Input.GetKeyDown(KeyCode.RightArrow))
        {
            audioSource.time += 1.0f;
            startDspTime -= 1.0f;
        }
    }

    // Simple implementations of Combo, Score UIs
    // It needs to be changed if PlayEngine don't have any responsibilities of score & combo
    public void HandleNoteJudge(JudgeType type)
    {
        if (type == JudgeType.Ignore)
            return;
        combo = type != JudgeType.Miss ? combo + 1 : 0;
        score += (int)type;

        IngameUIManager.inst.UpdateComboUI(combo);
        IngameUIManager.inst.UpdateScoreUI(score);
    }
    //
}

public class PlayerInput
{
    // TODO: make'em properties
    public Ray ray;
    public HandType hand;
    public double time;
}