using Assets.Scripts.Constants;
using System;
using System.Linq;
using UnityEngine;

public class WispMechanicController : MonoBehaviour
{
    private int[] correctPositions;
    private int[] currentPositions;
    private MousePointer currentPointer = MousePointer.Normal;

    public Action OnSequenceMatched;

    public Material LightSourceMaterial;
    public Material StringMaterial;
    public Material CapoMaterial;

    public bool CanSolvePuzzle = false;
    private bool _wasDialoguePrompted = false;

    void Start()
    {
        correctPositions = CreateLightSourcesPositions();
        currentPositions = CreateCapoCurrentPositions(correctPositions);
    }

    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            HandleSlotMoved();
            if(CanSolvePuzzle)
            {
                CheckIfSlotsMatch();
            }
        }
    }

    void HandleSlotMoved()
    {
        Ray mousePosRay = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        if (Physics.Raycast(mousePosRay, out hit))
        {
            MoveCapoSlot(hit.transform.gameObject.name);
            print(string.Format("{0}, {1}, {2}", currentPositions[0], currentPositions[1], currentPositions[2]));
        }
    }

    void MoveCapoSlot(string stringSlot)
    {
        if (!WispCapos.CapoMappings.ContainsKey(stringSlot))
            return;

        int capoColumnId = WispCapos.CapoMappings[stringSlot];
        int currentCapoSlot = currentPositions[capoColumnId];
        int newCapoSlot = currentCapoSlot;
        newCapoSlot = ++(newCapoSlot) % 3;
        currentPositions[capoColumnId] = newCapoSlot;

        GameObject stringSlotGameObject = GameObject.Find(stringSlot);
        SetCapoVisibility(stringSlotGameObject.transform.GetChild(currentCapoSlot).gameObject, false);
        SetCapoVisibility(stringSlotGameObject.transform.GetChild(newCapoSlot).gameObject, true);

        if (!_wasDialoguePrompted)
        {
            PromptDialog();
            _wasDialoguePrompted = true;
        }
    }

    void PromptDialog()
    {
        FindObjectOfType<DialogueManager>().PlaySequence(DialoguerDialogues.OnViewHarp);
    }

    bool CheckIfSlotsMatch(bool notify = true)
    {
        if (Enumerable.SequenceEqual(correctPositions, currentPositions))
        {
            if (OnSequenceMatched != null)
            {
                if (notify)
                {
                    OnSequenceMatched();
                }                
            }
            else
            {
                print("Pattern matched but found no handler to notify");
            }
            return true;
        }
        return false;
    }

    int[] CreateLightSourcesPositions()
    {
        GameObject lightSourceColumnOne = GameObject.Find(WispLightSources.LightSourceColumn1);
        GameObject lightSourceColumnTwo = GameObject.Find(WispLightSources.LightSourceColumn2);
        GameObject lightSourceColumnThree = GameObject.Find(WispLightSources.LightSourceColumn3);

        return new int[] {
            SelectRandomChildTile(lightSourceColumnOne, LightSourceMaterial),
            SelectRandomChildTile(lightSourceColumnTwo, LightSourceMaterial),
            SelectRandomChildTile(lightSourceColumnThree, LightSourceMaterial)
        };
    }

    int[] CreateCapoCurrentPositions(int[] valuesToOmit)
    {
        GameObject capoColumnOne = GameObject.Find(WispCapos.CapoColumn1);
        GameObject capoColumnTwo = GameObject.Find(WispCapos.CapoColumn2);
        GameObject capoColumnThree = GameObject.Find(WispCapos.CapoColumn3);

        return new int[] {
            SelectRandomCapo(capoColumnOne, valuesToOmit[0]),
            SelectRandomCapo(capoColumnTwo, valuesToOmit[1]),
            SelectRandomCapo(capoColumnThree, valuesToOmit[2])
        };
    }

    int SelectRandomChildTile(GameObject gameObject, Material material, int valueToOmit = -1)
    {
        int rand = UnityEngine.Random.Range(0, 3);
        gameObject.transform.GetChild(rand).gameObject.GetComponent<Renderer>().material = material;
        return rand;
    }


    int SelectRandomCapo(GameObject column, int valueToOmit)
    {
        int rand;
        do
        {
            rand = UnityEngine.Random.Range(0, 2);
        }
        while (rand == valueToOmit);

        GameObject capo = column.transform.GetChild(rand).gameObject;
        SetCapoVisibility(capo, true);
        return rand;
    }

    void SetCapoVisibility(GameObject capo, bool isVisible)
    {
        capo.GetComponent<MeshRenderer>().enabled = isVisible;
    }

}