using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

public sealed class Base : MonoBehaviour
{
    [SerializeField]
    private MeshRenderer[] renderers = null;
    [SerializeField]
    private float resourceCollectionTime = 2f;
    [SerializeField]
    private Vector3 incomeEffectPosition = Vector3.zero;
    [SerializeField]
    private TextEffectController textEffect = null;
    [SerializeField]
    private BlueprintProvider blueprintProvider = null;
    [SerializeField]
    private UnitFactory unitFactory = null;
    [SerializeField]
    private Army defenceArmy = null;
    [SerializeField]
    private float minSelectionRadius = 0.5f;
    [SerializeField]
    private bool isMainBase = false;

    public readonly List<StructureBlueprint> Structures = new List<StructureBlueprint>();

    public Faction Faction { get; private set; }
    public bool IsMainBase => isMainBase;

    public int FactionId => Faction.ID;

    public float FireRange => defenceArmy.Lives > 0 ? defenceArmy.FireRange : 0;

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

    private int resourceIncome = 0;
    private float resourceTimer = 0;
    private StringBuilder props = new StringBuilder();

    public void Init(Faction faction)
    {
        Faction = faction;
        Faction?.AddBase(this);
        defenceArmy.Init(Faction.ID, Faction.Color);
        SetColor(Faction.Color);
        // Build resource
        FinishProject("resource_collection");
    }

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

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

    private void FinishProject(string projectId)
    {
        if (this == null)
            return;
        var unitBlueprint = blueprintProvider.Units.Where(blueprint => blueprint.ID == projectId).FirstOrDefault();
        if (unitBlueprint != null)
        {
            defenceArmy.AddUnit(new Vehicle(unitBlueprint, UnityEngine.Random.Range(0, 1f)));
            return;
        }
        var structureBlueprint = blueprintProvider.Structures.Where(blueprint => blueprint.ID == projectId).FirstOrDefault();
        if (structureBlueprint != null)
        {
            AddStructure(structureBlueprint);
            return;
        }
        if (projectId == "officer") {
            var officer = unitFactory.CreateArmy(Faction, transform.position);
            var startOffset = Random.insideUnitCircle.normalized * Radius * 1.5f;
            officer.MoveTo(transform.position + new Vector3(startOffset.x, 0, startOffset.y));
            return;
        }
        Debug.LogError("finish project " + projectId);
    }

    public ProjectBlueprint[] GetAvailableProjects() => isMainBase ? blueprintProvider.BaseProjects : blueprintProvider.OutpostProjects;

    public string GetDescription()
    {
        props.Clear();
        props.Append($"{Faction.Name} base");
        foreach (var strucutre in Structures)
            props.Append($"\n{strucutre.ID}");
        return props.ToString();
    }

    private void AddStructure(StructureBlueprint structure) {
        Structures.Add(structure);
        UpdateProperties(Structures);
    }

    private void UpdateProperties(List<StructureBlueprint> structures)
    {
        resourceIncome = 0;
        foreach (var structure in structures) {
            switch (structure.Type) {
                case StructureBlueprint.StructureType.ResourceCollection:
                    resourceIncome += structure.Count;
                    break;
            }
        }
    }

    private void OnDestroy()
    {
        Faction?.RemoveBase(this);
    }

    private void SetColor(Color color)
    {
        if (renderers == null)
            return;

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

    private void Update()
    {
        CollectResources();
    }

    private void CollectResources()
    {
        if (resourceIncome <= 0)
            return;
        resourceTimer -= Time.deltaTime;
        if (resourceTimer < 0) {
            resourceTimer += resourceCollectionTime;
            Faction.AddResources(resourceIncome);
            textEffect.Show($"+{resourceIncome}", transform.position + incomeEffectPosition);
        }
    }

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