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

/// <summary>
/// Enemy_4 will start offscreen and then pick a random point on screen to
///   move to. Once it has arrived, it will pick another random point and
///   continue until the player has shot it down.
/// </summary>

[System.Serializable]
public class Part {
    // These three fields need to be defined in the Inspector pane
    public string name;
    public float health;
    public string[] protectedBy;
    [HideInInspector]
    public GameObject go;
    [HideInInspector]
    public Material mat;
}

public class Enemy_4 : Enemy
{
    [Header("Set in Inspector: Enemy_4")]
    public Part[] parts;
    private Vector3 p0, p1; // The two points to interpolate
    private float timeStart; // Birth time for this Enemy_4
    private float duration = 4; // Duration of movement

    void Start()
    {
        // There is already an initial position chosen by Main.SpawnEnemy()
        //  so add it to points as the initial p0 & p1
        p0 = p1 = pos;
        InitMovement();
        Transform t;
        foreach(Part prt in parts) {
            t = transform.Find(prt.name);
            if (t != null) {
                prt.go = t.gameObject;
                prt.mat = prt.go.GetComponent<Renderer>().material;
            }
        }
    }

    void InitMovement() {
        p0 = p1; // Set p0 to the old p1
        // Assign a new on-screen location to p1
        float widMinRad = bndCheck.camWidth - bndCheck.radius;
        float hgtMinRad = bndCheck.camHeight - bndCheck.radius;
        p1.x = Random.Range(-widMinRad, widMinRad);
        p1.y = Random.Range(-hgtMinRad, hgtMinRad);
        // Reset the time
        timeStart = Time.time;
    }
    public override void Move() {
        // This completely overrides Enemy.Move() with a linear interpolation
        float u = (Time.time - timeStart) / duration;
        if (u >= 1) {
            InitMovement();
            u = 0;
        }
        u = 1 - Mathf.Pow(1 - u, 2); // Apply East Out easing to u
        pos = (1 - u) * p0 + u*p1; // Simple linear interpolation
    }

    // These two functions find a Part in parts based on name or GameObject
    Part FindPart(string n) {
        foreach(Part prt in parts) {
            if (prt.name == n) {
                return prt;
            }
        }
        return null;
    }

    Part FindPart(GameObject go) {
        foreach(Part prt in parts) {
            if (prt.go == go) {
                return prt;
            }
        }
        return null;
    }

    // These functions return true if the Part has been destroyed
    bool Destroyed(GameObject go) {
        return Destroyed(FindPart(go));
    }
    
    bool Destroyed(string n) {
        return Destroyed(FindPart(n));
    }
    
    bool Destroyed(Part prt) {
        if (prt == null) {
            return true;
        }
        return prt.health <= 0;
    }

    // This changes the color of just one Part to red instead of the whole ship
    void ShowLocalizedDamage(Material m) {
        m.color = Color.red;
        damageDoneTime = Time.time + showDamageDuration;
        showingDamage = true;
    }
    
    // This will override the OnCollisionEnter that is part of Enemy.cs
    void OnCollisionEnter(Collision coll) {
        GameObject other = coll.gameObject;
        switch (other.tag) {
            case "ProjectileHero":
                Projectile p = other.GetComponent<Projectile>();
                // If this Enemy is off screen, don't damage it.
                if (!bndCheck.isOnScreen) {
                    Destroy(other);
                    break;
                }
                // Hurt this Enemy
                GameObject goHit = coll.contacts[0].thisCollider.gameObject;
                Part prtHit = FindPart(goHit);
                if (prtHit == null) {
                    goHit = coll.contacts[0].otherCollider.gameObject;
                    prtHit = FindPart(goHit);
                }
                // Check whether this part is still protected
                if (prtHit.protectedBy != null) {
                    foreach(string s in prtHit.protectedBy) {
                        // If one of the protecting parts hasn't been destroyed...
                        if (!Destroyed(s)) {
                            // ...then don't damage this part yet
                            Destroy(other);
                            return;
                        }
                    }
                }
                prtHit.health -= 1;
                ShowLocalizedDamage(prtHit.mat);
                if (prtHit.health <= 0) {
                    prtHit.go.SetActive(false);
                }
                bool allDestroyed = true;
                foreach (Part prt in parts) {
                    if (!Destroyed(prt)) {
                        allDestroyed = false;
                        break;
                    }
                }
                if (allDestroyed) {
                    Main.S.ShipDestroyed(this);
                    Destroy(this.gameObject);
                }
                Destroy(other);
                break;
        }
    }
}
