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;

    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;
            level.UpdateNotes(playbackTime);

            PlayerInput input = new PlayerInput();
            input.time = 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))
                {
                }
                if (fire.GetStateDown(rightHand))
                {
                }
            }
            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;
}