using AlienAttack.MonoGame.Things.Bullets;
using AlienAttack.MonoGame.Things.Muzzles;
using Microsoft.Xna.Framework;
using System.Linq;

namespace AlienAttack.MonoGame.Things.Weapons;

public abstract class Weapon : IWeapon
{
    public abstract int FireThreshold { get; }
    public int CurrentFireThreshold { get; private set; }

    public void UpdateFireThreshold()
    {
        if (CurrentFireThreshold > 0)
            CurrentFireThreshold--;
    }

    public bool TryFire(Sprite owner, SpriteUpdateContext context)
    {
        if (CurrentFireThreshold > 0)
            return false;

        Fire(owner, context);
        CurrentFireThreshold = FireThreshold;

        return true;
    }

    public abstract void Fire(Sprite owner, SpriteUpdateContext context);

    protected static void FireBullet(FireBulletContext context)
    {
        var (x, y) = ComputeAnchorPosition(context);

        foreach (Shot shot in context.Shots)
        {
            Bullet bullet = context.Factory(x + shot.OffsetX, y + shot.OffsetY, shot.XVelocity, shot.YVelocity, context.Owner);
            context.SpriteUpdateContext.SpawnSprite(bullet);
        }
    }

    private static (float x, float y) ComputeAnchorPosition(FireBulletContext context)
    {
        Sprite owner = context.Owner;
        int bw = context.BulletWidth;
        int bh = context.BulletHeight;
        Anchor anchor = context.Anchor;

        float left = owner.XPosition;
        float top = owner.YPosition;
        float right = owner.XPosition + owner.BoundBox.Width;
        float bottom = owner.YPosition + owner.BoundBox.Height;

        return anchor switch
        {
            Anchor.TopLeft => (left, top - bh),
            Anchor.TopCenter => (left + (owner.BoundBox.Width - bw) / 2f, top - bh),
            Anchor.TopRight => (right - bw, top - bh),

            Anchor.Center => (left + (owner.BoundBox.Width - bw) / 2f, top + (owner.BoundBox.Height - bh) / 2f),

            Anchor.BottomLeft => (left, bottom),
            Anchor.BottomCenter => (left + (owner.BoundBox.Width - bw) / 2f, bottom),
            Anchor.BottomRight => (right - bw, bottom),

            _ => (left, top)
        };
    }

    protected static void FireFromMuzzle(FireBulletFromMuzzleContext context)
    {
        if (context.Owner is not Player player)
            return;

        foreach (MuzzleShot shot in context.Shots)
        {
            var m = player.Muzzles.First(x => x.Id == shot.Muzzle).LocalPx;
            Vector2 worldMuzzle = MuzzleMath.GetMuzzleWorld(player, m);
            Vector2 bulletPos = MuzzleMath.CenterBulletOn(worldMuzzle, context.BulletWidth, context.BulletHeight) + context.ExtraOffset;

            Bullet bullet = context.Factory(bulletPos.X, bulletPos.Y, shot.XVelocity, shot.YVelocity, context.Owner);
            context.SpriteUpdateContext.SpawnSprite(bullet);
        }
    }
}