using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.SocialPlatforms.Impl;
using UnityEngine.UI;

public class Target
{
    public FoodType Type;
    public int Number;

    public Target(FoodType t, int n)
    {
        Type = t;
        Number = n;
    }
}

public class GameController : MonoBehaviour
{
    //a class for keeping scores, trigger game over, initiate objects, etc.
    public static GameController Instance;

    public Rect SpawnArea_L;
    public Rect SpawnArea_R;
    public Rect SpawnArea_Btm;
    public Rect WanderArea;
    public List<Transform> WanderPoints;
    public Player PlayerController;
    public CameraController CameraCtrl;
    public ShakeEffect KingShakeEffect;
    public ShakeEffect BubbleShakeEffect;
    public float ShakeTime = 0.04f;
    //public Image Img;
    //public Text Number;
    public Text TargetText;
    public List<LevelConfig> LevelConfigList;
    public List<FoodAsset> FoodAssetList;

    //settings
    public int max_teeth_fall = 3;
    public int min_teeth_fall = 1;
    public int num_sweets_to_teeth_fall = 5;
    public int num_sweets_subsequent_teeth_fall = 3;
    public bool IsBounceOpen = false;
    public float Deceleration = 1;

    //scorekeeping
    public int current_score;

    //result display
    public GameObject success_panel;
    public GameObject failure_panel;

    //level title
    public GameObject level_title;

    //freeze (result display & effect)
    public bool isfrozen;

    //king
    public King king;

    //laugh bar
    public LaughBar laugh_bar;

    //audio
    public AudioClip soundSamples;
    public AudioClip soundSamples2;
    private AudioSource audioSource;

    private LevelConfig currentLevelConfig;
    public FoodType TargetFoodType
    {
        get { return current_target.Type; }
    }

    public int TargetFoodNumber
    {
        get { return current_target.Number; }
    }

    private int currentLevel = 0;
    private List<float> timeCountList = new List<float>();
    private Dictionary<FoodType, int> foodMap = new Dictionary<FoodType, int>();
    private Target current_target;

    //
    public bool guideOn;

    void Awake()
    {
        Instance = this;
    }

    // Start is called before the first frame update
    void Start()
    {
        audioSource = GetComponent<AudioSource>();
        foodMap.Clear();
        timeCountList.Clear();
        if(guideOn)
        {
            level_title.SetActive(false);
            isfrozen = true;
        }else
        {
            level_title.SetActive(true);
            isfrozen = false;
        }
        

        currentLevelConfig = LevelConfigList[currentLevel];
        current_target= new Target(currentLevelConfig.TargetFoodType, currentLevelConfig.TargetFoodNumber);
        if(currentLevelConfig.TargetFoodType == FoodType.Teeth)
        {
            king.SetBadToothNumber(currentLevelConfig.TargetFoodNumber, true);
        }

        laugh_bar.initial_score = currentLevelConfig.InitialScore;
        laugh_bar.total_score = currentLevelConfig.TotalScore;


        //var asset = FoodAssetList.Find(x => x.Type == TargetFoodType);
        //Img.sprite = asset.Sp;
        //Number.text = $"x{currentLevelConfig.TargetFoodNumber}";
        TargetText.text = TargetFoodType.ToString() + "!";
        foreach(var ele in currentLevelConfig.FoodList)
        {
            timeCountList.Add(ele.StartDelay + Random.Range(ele.RefreshIntervalLower, ele.RefreshIntervalUpper));
            foodMap[ele.Type] = 0;
        }

        //initial score
        //testing; should be 0
        current_score = (int)currentLevelConfig.InitialScore;
    }

    // Update is called once per frame
    void Update()
    {
        //Debug.Log(TargetFoodNumber);
        if (!isfrozen)
        {
            if (TargetFoodNumber == 0)
            {
                //current_target=nextTarget();
                //var asset = FoodAssetList.Find(x => x.Type == TargetFoodType);
                //Img.sprite = asset.Sp;
                //Number.text = $"x{TargetFoodNumber}";
                switchTarget();

            }


            for (int i = 0; i < currentLevelConfig.FoodList.Count; i++)
            {
                var levelFoodConfig = currentLevelConfig.FoodList[i];
                timeCountList[i] = timeCountList[i] - Time.deltaTime;
                if (timeCountList[i] < 0)
                {
                    timeCountList[i] = Random.Range(levelFoodConfig.RefreshIntervalLower, levelFoodConfig.RefreshIntervalUpper);
                    if (foodMap[levelFoodConfig.Type] < levelFoodConfig.MaxNumber)
                    {
                        //get max number to be generated
                        int num = levelFoodConfig.MaxNumber - foodMap[levelFoodConfig.Type];
                        //make sure does not exceed max number
                        num = Mathf.Min(Random.Range(levelFoodConfig.RefreshNumLower, levelFoodConfig.RefreshNumUpper + 1), num);
                        for (int ii = 0; ii < num; ii++)
                        {
                            var asset = FoodAssetList.Find(x => x.Type == levelFoodConfig.Type);
                            var go = Instantiate(asset.Prefab);
                            FoodObject foodObj = go.GetComponent<FoodObject>();
                            if (foodObj != null)
                            {
                                ResetFoodSpeed(foodObj);
                            }

                            float which_area = Random.Range(0f, 100f);
                            if (which_area <= 10)
                            {
                                go.transform.position = new Vector3(SpawnArea_L.x + Random.Range(0, SpawnArea_L.width), SpawnArea_L.y + Random.Range(0, SpawnArea_L.height), 0);
                            }
                            else if (which_area <= 20)
                            {
                                go.transform.position = new Vector3(SpawnArea_R.x + Random.Range(0, SpawnArea_R.width), SpawnArea_R.y + Random.Range(0, SpawnArea_R.height), 0);
                            }
                            else
                            {
                                go.transform.position = new Vector3(SpawnArea_Btm.x + Random.Range(0, SpawnArea_Btm.width), SpawnArea_Btm.y + Random.Range(0, SpawnArea_Btm.height), 0);
                            }

                            foodMap[levelFoodConfig.Type]++;
                        }
                    }
                }
            }
        }
    }

    public Target nextTarget()
    {
        if(TargetFoodType == FoodType.Teeth)
        {
            return new Target(FoodType.Suger, num_sweets_to_teeth_fall);
        }
        else
        {
            var number = Random.Range(min_teeth_fall, max_teeth_fall + 1);
            king.SetBadToothNumber(number);
            return new Target(FoodType.Teeth, number);
        }
    }

    public void switchTarget()
    {
        current_target = nextTarget();

        FoodObject[] allFoodInScene = FindObjectsOfType<FoodObject>();
        foreach(FoodObject food in allFoodInScene)
        {
            ResetFoodSpeed(food);
        }
        TargetText.text = CheckTargetFood(FoodType.Suger)? "CANDY!": "TEETH!";
    }

    public void ResetFoodSpeed(FoodObject food)
    {
        if (CheckTargetFood(food.foodType))
        {
            food.moveSpeed = currentLevelConfig.TargetMoveSpeed;
            food.hitspeed = currentLevelConfig.TargetHitSpeed;
            food.originHitSpeed = currentLevelConfig.TargetHitSpeed;

        }
        else
        {
            food.moveSpeed = currentLevelConfig.NonTargetMoveSpeed;
            food.hitspeed = currentLevelConfig.NonTargetHitSpeed;
            food.originHitSpeed = currentLevelConfig.NonTargetHitSpeed;
        }
    }

    public void DestroyFood(FoodType type)
    {
        if(foodMap.ContainsKey(type)){
            for (int i = 0; i < currentLevelConfig.FoodList.Count; i++)
            {
                var levelFoodConfig = currentLevelConfig.FoodList[i];
                if(levelFoodConfig.MaxNumber == foodMap[type])
                    timeCountList[i] = Random.Range(levelFoodConfig.RefreshIntervalLower, levelFoodConfig.RefreshIntervalUpper);
            }
            foodMap[type]--;
        }
    }

    public void EatFood(FoodType type)
    {
        DestroyFood(type);

        if (CheckTargetFood(type))
        {
            Scored();
            current_target.Number-- ;
            //Number.text = $"x{current_target.Number}";
        }
        else
        {
            LostPoint();
        }
    }

    public void Scored()
    {
        current_score++;
        laugh_bar.calculateLength(current_score);
        if(current_score >= currentLevelConfig.TotalScore)
        {
            freeze();
            audioSource.PlayOneShot(soundSamples);
            success_panel.SetActive(true);
        }
            //SceneManager.LoadScene("Success_lv1");

    }

    public void LostPoint()
    {
        current_score--;
        laugh_bar.calculateLength(current_score);
        if (current_score <= 0)
        {
            freeze();
            audioSource.PlayOneShot(soundSamples2);
            failure_panel.SetActive(true);
            //SceneManager.LoadScene("Fail_lv1");
        }

    }

    public void freeze()
    {
        isfrozen = true;
        FoodObject[] allFoodInScene = FindObjectsOfType<FoodObject>();
        foreach (FoodObject food in allFoodInScene)
        {
            food.isfrozen = true;
        }
        Player p = GameObject.Find("player_cat").GetComponent<Player>();
        p.isfrozen = true;
    }

    public Vector3 GetRandomWanderPoint()
    {
        //int index = Random.Range(0, WanderPoints.Count);
        //return WanderPoints[index].position;
        return new Vector3(WanderArea.x + Random.Range(0, WanderArea.width), WanderArea.y + Random.Range(0, WanderArea.height), 0);
    }

    public bool CheckTargetFood(FoodType type)
    {
        if (type == TargetFoodType) return true;
        if (type == FoodType.GoldenTeeth && TargetFoodType == FoodType.Teeth) return true;
        return false;
    }

    //to close guide
    public void closeGuide(GameObject guide)
    {
        guide.SetActive(false);
        isfrozen = false;
        level_title.SetActive(true);
    }

    public void Shake()
    {
        CameraCtrl.StartShake(0.5f, 0.5f, 0f, ShakeTime, 5, 2);
        KingShakeEffect.StartShake(0.5f, 0.5f, 0f, ShakeTime, 5, 2);
        BubbleShakeEffect.StartShake(10f, 10f, 0f, ShakeTime, 5, 2);
    }
}
