using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Hand : MonoBehaviour
{
    public Card CardPrefab;
    public LineRenderer Pointer;
    private int CardCount = 10;

    private List<Card> Cards = new List<Card>();
    private Camera Cam;
    
    private Card StartDrag = null;
    private Vector3 DragMouseStart;
    private Pile LastHoverPile = null;
    private Card LastHoverCard = null;

    private Button LastButton = null;

    private int MoneyCount = 0;
    private int MoneyVisible = 0;
    private TMPro.TextMeshPro CounterText;

    private int StarCount = 3;
    private TMPro.TextMeshPro StarCounterText;

    private int TotalCardSold = 0;
    private TMPro.TextMeshPro TotalCardSoldText;
    private TMPro.TextMeshPro CardInHandText;

    private List<Pile> Piles = new List<Pile>();

    private bool ShowHelp = false;
    public Transform HelpElement = null;

    private bool ShowPause = false;
    public Transform PauseElement = null;

    public static Vector3 Bezier(Vector3 P0, Vector3 P1, Vector3 P2, Vector3 P3, float Alpha)
    {
        float t = Mathf.Clamp01(Alpha);
        float it = 1f - t;

        return it * it * it * P0
             + 3f * it * it * t * P1
             + 3f * it * t * t * P2
             + t * t * t * P3;
    }

    void UpCardPositions()
    {
        bool PressLeft = Input.GetMouseButtonDown(0);
        Vector3 WorldMousePos = Cam.ScreenToWorldPoint(Input.mousePosition);

        if(Input.GetKeyDown(KeyCode.Escape))
        {
            StartDrag = null;
            ShowPause = !ShowPause;
            PauseElement.gameObject.SetActive(ShowPause);
            if (ShowHelp)
            {
                ShowHelp = false;
                HelpElement.gameObject.SetActive(ShowHelp);
            }
        }

        Collider2D[] HoverAll = Physics2D.OverlapPointAll(new Vector2(WorldMousePos.x, WorldMousePos.y));
        Pile CurrentHover = null;
        Button CurrentButton = null;
        for (int i = 0; i < HoverAll.Length; ++i)
        {
            Collider2D Cur = HoverAll[i];
            //Debug.Log("Cur : " + Cur.name);
            if (Cur)
            {
                Pile CurPile = Cur.GetComponent<Pile>();
                if (CurPile)
                {
                    CurrentHover = CurPile;
                    break;
                }
                Button CurButton = Cur.GetComponent<Button>();
                if(CurButton && !StartDrag) // only check for button if not dragging
                {
                    CurrentButton = CurButton;
                    if(PressLeft)
                    {
                        if (!ShowHelp && !ShowPause)
                        {
                            if (CurButton.Type == ButtonType.Refill)
                            {
                                UseStar();
                            }
                            if (CurButton.Type == ButtonType.Reset)
                            {
                                Reset();
                            }
                        }
                        if(!ShowPause)
                        {
                            if (CurButton.Type == ButtonType.Help)
                            {
                                ShowHelp = !ShowHelp;
                                HelpElement.gameObject.SetActive(ShowHelp);
                            }
                        }
                        else
                        {
                            if (CurButton.Type == ButtonType.Quit)
                            {
                                Application.Quit();
                            }
                            if (CurButton.Type == ButtonType.CancelQuit)
                            {
                                ShowPause = !ShowPause;
                                PauseElement.gameObject.SetActive(ShowPause);
                            }
                        }
                        
                    }
                }
            }
        }

        bool JustReleased = false;
        if (StartDrag)
        {
            Pointer.gameObject.SetActive(true);
            int PointerCount = 100;
            Vector3 StartPos = new Vector3(DragMouseStart.x, DragMouseStart.y, -45f);
            Vector3 FirstHandle = new Vector3(StartPos.x, StartPos.y + 1f, StartPos.z);
            Vector3 EndPos = new Vector3(WorldMousePos.x, WorldMousePos.y, StartPos.z);
            Vector3 SecondHandle = new Vector3(EndPos.x, EndPos.y - 1f, EndPos.z);
            Vector3[] Positions = new Vector3[PointerCount];
            for (int i = 0; i < PointerCount; ++i)
            {
                float Alpha = i / (PointerCount - 1f);
                Positions[i] = Bezier(StartPos, FirstHandle, SecondHandle, EndPos, Alpha);
            }
            Pointer.positionCount = PointerCount;
            Pointer.SetPositions(Positions);

            if (!Input.GetMouseButton(0)) // Release
            {
                if (CurrentHover && CurrentHover.CurrentCard)
                {
                    JustReleased = true;
                    //Debug.Log("Release mouse");
                    Vector3 CardPos = StartDrag.transform.localPosition;
                    CardPos.z = 10.0f;
                    StartDrag.transform.localPosition = CardPos;
                    Interpol NewInterpol = StartDrag.gameObject.AddComponent<Interpol>();
                    NewInterpol.DestroyOnArrival = true;
                    NewInterpol.TransformGoal = CurrentHover.CurrentCard.transform;
                    NewInterpol.Goal = new Vector3(0, 0, 10.0f);
                    int MoneyGain = StartDrag.Price * CurrentHover.CurrentCard.PriceMult;
                    int CardGain = StartDrag.CardGain * CurrentHover.CurrentCard.CardMult;
                    int StarGain = StartDrag.StarGain * CurrentHover.CurrentCard.StarMult;
                    bool IsEnded = CurrentHover.ApplyCard(StartDrag);
                    Cards.Remove(StartDrag);
                    if (IsEnded)
                    {
                        //NewInterpol.Goal = new Vector3(14, 2, 10.0f);
                        AddMoney(MoneyGain);
                        AddStars(StarGain);
                        RefillCards(CardGain);
                    }
                    else
                    {
                        //NewInterpol.Goal = new Vector3(CurrentHover.transform.position.x, CurrentHover.transform.position.y, 10.0f);
                    }
                    //GameObject.Destroy(StartDrag.gameObject);
                    StartDrag = null;
                }
                StartDrag = null;
            }
            else
            {
                /*
                if (CurrentHover && CurrentHover.CurrentCard)
                {
                    CurrentHover.CurrentCard.PreviewCard(StartDrag);
                    StartDrag.PreviewCard(CurrentHover.CurrentCard);
                }
                else
                {
                    StartDrag.StopPreview();
                }
                */
            }
            Pointer.transform.position = EndPos;
        }
        else
        {
            Pointer.gameObject.SetActive(false);
            DragMouseStart = WorldMousePos;
        }


        float MouseX = DragMouseStart.x;
        float MouseY = DragMouseStart.y;


        float CardSize = 1.6f;
        float TravelSpeed = 3.0f;

        float ClosestDist = 10000.0f;
        Card ClosestCard = null;
        float HalfSize = Cards.Count * .5f;
        bool CardHover = MouseY < -1.0f && Mathf.Abs(MouseX) < CardSize * (HalfSize + 0.5f) && !JustReleased && !ShowHelp;

        for (int i = 0; i < Cards.Count; ++i)
        {
            Card CurCard = Cards[i];
            Vector3 NewPos = transform.position;
            NewPos.x += CardSize * (-HalfSize + 0.5f + i);
            if (CardHover)
            {   
                float Dist = Mathf.Abs(NewPos.x - MouseX);
                if (ClosestDist > Dist)
                {
                    ClosestDist = Dist;
                    ClosestCard = CurCard;
                }
                NewPos.y += 5.0f / (Dist + 2.0f);
            }
            NewPos.z += 2.0f * i;
            float Perc = TravelSpeed * Time.deltaTime;
            NewPos.x = Mathf.Lerp(CurCard.transform.position.x, NewPos.x, Perc);
            NewPos.y = Mathf.Lerp(CurCard.transform.position.y, NewPos.y, Perc);
            CurCard.transform.position = NewPos;
        }

        if (ClosestCard)
        {
            Vector3 CardPos = ClosestCard.transform.position;
            CardPos.z = -40.0f; 
            ClosestCard.transform.position = CardPos;
            if(PressLeft)
            {
                StartDrag = ClosestCard;
            }
        }
        if (ClosestCard)
        {
            for (int i = 0; i < Piles.Count; ++i)
            {
                Card PileCard = Piles[i].CurrentCard;
                if (PileCard)
                {
                    PileCard.PreviewCard(ClosestCard);
                }
            }
        }
        else
        {
            for (int i = 0; i < Piles.Count; ++i)
            {
                Card PileCard = Piles[i].CurrentCard;
                if (PileCard)
                {
                    PileCard.StopPreview();
                }
            }
        }

        if (ClosestCard != LastHoverCard)
        {
            if (ClosestCard) ClosestCard.StartHover();
            if (LastHoverCard) LastHoverCard.StopHover();
        }
        LastHoverCard = ClosestCard;
        if (CurrentHover != LastHoverPile)
        {
            if (CurrentHover) CurrentHover.StartHover();
            if (LastHoverPile) LastHoverPile.StopHover();
        }
        LastHoverPile = CurrentHover;
        if (CurrentButton != LastButton)
        {
            if (CurrentButton) CurrentButton.StartHover();
            if (LastButton) LastButton.StopHover();
        }
        LastButton = CurrentButton;
    }

    public void UseStar()
    {
        if(StarCount>0)
        {
            StarCount-=1;
            RefillCards(5);
        }
    }

    void RefillCards(int MaxCardAdd)
    {
        int AddingCount = Mathf.Min(MaxCardAdd, Mathf.Max(0, CardCount - Cards.Count));
        for (int i = 0; i < AddingCount; ++i)
        {
            GameObject NewCardObj = GameObject.Instantiate(CardPrefab.gameObject);
            Card NewCard = NewCardObj.GetComponent<Card>();
            NewCard.Price = 100 * Random.Range(1, 5);
            NewCard.CardGain = Random.Range(0, 3);
            NewCard.StarGain = (Random.value < Mathf.Exp(-2-TotalCardSold*0.1f)) ? 1 : 0; // TODO better average
            NewCard.transform.position = new Vector3(10, 2, 0);
            Cards.Add(NewCard);
        }
    }

    void Reset()
    {
        StartDrag = null;
        for (int i=0; i<Cards.Count; ++i)
        {
            GameObject.Destroy(Cards[i].gameObject);
        }
        Cards.Clear();

        for (int i = 0; i < Piles.Count; ++i)
        {
            Piles[i].ResetPile();
        }
        StarCount = 3;
        MoneyCount = 0;
        TotalCardSold = 0;
        MoneyVisible = MoneyCount;
        RefillCards(5);
    }

    public void AddMoney(int Value)
    {
        TotalCardSold += 1;
        MoneyCount += Value;
    }

    public void AddStars(int Value)
    {
        StarCount += Value;
    }

    // Start is called before the first frame update
    void Start()
    {
        Cam = Camera.main;
        CounterText = GameObject.Find("Counter").transform.GetChild(0).GetComponent<TMPro.TextMeshPro>();
        StarCounterText = GameObject.Find("StarCounter").transform.GetChild(0).GetComponent<TMPro.TextMeshPro>();
        TotalCardSoldText = GameObject.Find("CardInSold").GetComponent<TMPro.TextMeshPro>();
        CardInHandText = GameObject.Find("CardInHand").GetComponent<TMPro.TextMeshPro>();
        //HelpElement = GameObject.Find("Help").transform;
        HelpElement.gameObject.SetActive(ShowHelp);
        Piles.AddRange(GameObject.FindObjectsOfType<Pile>());
        Reset();
    }

    // Update is called once per frame
    void Update()
    {
        UpCardPositions();

        MoneyVisible = MoneyVisible + Mathf.CeilToInt((MoneyCount - MoneyVisible)/10.0f);
        CounterText.text = MoneyVisible + "<sprite index=2>";

        StarCounterText.text = StarCount + "<sprite index=3>";

        TotalCardSoldText.text = TotalCardSold + "<sprite index=1> sold";
        CardInHandText.text = Cards.Count + "/" + CardCount + "<sprite index=1>";
    }
}
