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


using System.Linq;

public abstract class BaseWeaponChanger : MonoBehaviour
{
    // the list of weapons this character has
    [SerializeField]
    private List<Weapon> weapons = null; 
    
    // indicates if character should use random weapon
    [SerializeField]
    protected bool useRandomWeapon = false;

    [SerializeField, Range(0, 9)]
    private int currentWeapon = 0; // the currently active weapon

    // TODO: Create an event to broadcast when the character this script is attached to changes it weapon
    [SerializeField, Header("Register to know when I change my weapon.")]
    protected WeaponChangeEvent weaponChange;

    // stores a list of valid weapon codes for this character
    protected List<string> weaponCodes;

    // used to cache the animator component attached to this character
    private Animator animator; 

    private void Awake()
    {
        // Initialise weapons
        InitialiseWeapons();

        // cache the animator component of the game object this script is attached to
        animator = GetComponent<Animator>();
    }

    // Start is called before the first frame update
    // Make Start protected and virtual, so that inherited classes can override and add to/replace Start logic
    protected virtual void Start()
    {
        // If use random weapon is true, select a random weapon

        // Else change the weapon to the current weapon
        if (useRandomWeapon)
        {
            SelectRandomWeapon();
        }
        else
        {
            ChangeWeapon(currentWeapon);
        }
    }

    // Update is called once per frame
    // Make Update protected and virtual, so that inherited classes can override and add to/replace Update logic
    protected virtual void Update()
    {
        // Get the key pressed
        string keyEntered = Input.inputString;

        // If key has been pressed and it is a valid weapon code, change the weapon to the new weapon with this code
        if (!string.IsNullOrEmpty(keyEntered) && weaponCodes.Contains(keyEntered))
        {
            ChangeWeapon(int.Parse(keyEntered));
        }
    }

    /// <summary>
    /// Method to initialise all weapons character has on startup
    /// </summary>
    private void InitialiseWeapons()
    {
        // Create a blank list of strings to store the valid weapon codes
        weaponCodes = new List<string>();

        // Loop through all the weapons defined for this character
        for (int i = 0; i < weapons.Count; i++)
        {
            // Enable the weapon if the current looping item index is the same as the currentWeapon value, otherwise disable it
            bool isEnabled = (i == currentWeapon);
            EnableWeapon(i, isEnabled);

            // Add the current looping index as a valid weapon code that can be used to change the current weapon
            weaponCodes.Add(i.ToString());

            // Loop though all weapons that make up the current weapon e.g. a bow and arrow has two weapons
            foreach (Renderer weaponRenderer in weapons[i].Models)
            {
                // Attach the weapon controller script to the current weapon renderer 
                WeaponController wc = weaponRenderer.gameObject.AddComponent<WeaponController>();

                // Set the weapon controller's weapon property to the current Weapon looping item
                wc.Weapon = weapons[i];
            }
        }

    }

    /// <summary>
    /// Change the currently active weapon to the weapon with the specified new index value
    /// </summary>
    /// <param name="newWeapon">The index number of the weapon to change to</param>
    protected void ChangeWeapon(int newWeapon)
    {
        // Check if the new weapon parameter is not the same as the current weapon - if the same, no need to do anything
        if (currentWeapon != newWeapon)
        {
            // Disable old weapons
            EnableWeapon(currentWeapon, false);

            // Enable new weapons
            EnableWeapon(newWeapon, true);

            // Update the current weapon
            currentWeapon = newWeapon;

            // Update the animator if animator component is not null
            if (animator != null)
            {
                animator.Rebind();
                animator.ResetTrigger("Use");
                animator.SetInteger("WeaponState", currentWeapon);
            }


            // Broadcast the event
            if (weaponChange != null)
                weaponChange.Invoke(weapons[newWeapon]);
        }
    }

    /// <summary>
    /// Reusable method to enable or disable weapons
    /// </summary>
    /// <param name="weapon">The index number of the weapon to enable or disable</param>
    /// <param name="isEnabled">Used to indicate if the weapon should be disabled or enabled</param>
    private void EnableWeapon(int weapon, bool isEnabled)
    {
        // Loop though all weapons that make up the current weapon e.g. a bow and arrow has two weapons

        // Enable or disable the weapon's renderer based on the value of the input parameter
        foreach (Renderer weaponRenderer in weapons[weapon].Models)
        {
            // Enable or disable the weapon based on the value of the input parameter
            weaponRenderer.enabled = isEnabled;

            // Make the weapon game object inactive/active based on whether it is the enabled weapon
            // If you do not make disabled weapons inactive, they will cause collisions
            weaponRenderer.gameObject.SetActive(isEnabled);
        }
    }

    protected void SelectRandomWeapon()
    {
        // generate a random index number between 0 and number of weapons-1 (collections are zero-based)
        

        // If the generated index number is not the same as the current weapon, KEEP TRYING (Hint: while loop) till you get a different one
        

        // Change the weapon using the random index generated
        
    }
}
