using System;
using System.Linq;
using UnityEngine;

/// <summary>
/// Moving army controller - can move army and buy units for it
/// </summary>
public sealed class Officer : MonoBehaviour
{
    [SerializeField]
    private MeshRenderer[] renderers = null;
    [SerializeField]
    private TextMesh livesCount = null;
    [SerializeField]
    private Army army = null;

    [SerializeField]
    private float speed = 1f;
    [SerializeField]
    private BlueprintProvider blueprints = null;
    [SerializeField]
    private float minSelectionRadius = 0.5f;

    public Faction Faction { get; private set; } = null;
    public int FactionId => Faction.ID;
    public float FireRange => army.FireRange;

    public float Radius => Mathf.Max(minSelectionRadius, army.Radius);

    public Vector3 TargetPosition = Vector3.zero;

    public string GetDescription()
    {
        return $"{Faction.Name} Army\nLives {army.Lives}";
    }

    public void StartProject(ProjectBlueprint blueprint)
    {
        BuildProject project = new BuildProject(blueprint.BuildTime, blueprint.ID, blueprint.ID, FinishProject);

        Faction.BuildProject(project, blueprint.Cost);
    }

    public void FinishProject(string projectId)
    {
        if (this == null)
            return;
        var unitBlueprint = blueprints.Units.Where(blueprint => blueprint.ID == projectId).FirstOrDefault();
        if (unitBlueprint == null) {
            throw new NullReferenceException($"building unit {projectId} not supported");
        }
        army.AddUnit(new Vehicle(unitBlueprint, UnityEngine.Random.Range(0f, 1f)));
    }

    public ProjectBlueprint[] GetAvailableProjects()
    {
        return blueprints.OfficerProjects;
    }

    public void Init(Faction newFaction)
    {
        Faction = newFaction;
        army.Init(Faction.ID, Faction.Color);
        SetColor(Faction.Color);
    }

    public void MoveTo(Vector3 position)
    {
        TargetPosition = position;
    }

    private void Awake()
    {
        army.SetAngle(UnityEngine.Random.Range(0, 360));
        livesCount.text = army.Lives.ToString();
    }

    private void Update()
    {
        ProcessMove();

        livesCount.text = army.Lives.ToString();
    }

    private void ProcessMove()
    {
        var direction = TargetPosition - transform.position;
        var moveDistance = speed * Time.deltaTime;
        if (direction.sqrMagnitude < moveDistance * moveDistance)
        {
            transform.position = TargetPosition;
        }
        else
        {
            transform.position += direction.normalized * moveDistance;
            var angle = Utils.GetAngle(new Vector2(direction.x, direction.z));
            army.SetAngle(angle);
        }
    }
    private void SetColor(Color color)
    {
        if (renderers == null)
            return;

        foreach (var renderer in renderers)
            renderer.material.color = color;
    }

    [ContextMenu("Find renderers")]
    private void FindRenderers()
    {
        renderers = GetComponentsInChildren<MeshRenderer>();
    }
}
