using System;
using KitsuneCafe.Entities;
using KitsuneCafe.Extension;
using KitsuneCafe.SOAP;
using R3;
using UnityEngine;

namespace KitsuneCafe.ItemSystem
{
    public class Firearm : MonoBehaviour, IEquippable, IDamaging
    {
        [SerializeField]
        private BoolValue ready;

        [SerializeField]
        private BoolValue fire;

        [SerializeField]
        private BoolValue reload;

        [SerializeField]
        private Transform projectileOrigin;

        [SerializeField]
        private DamageSource damageSource;

        [SerializeField]
        private float projectileLength = 15;

        [SerializeField]
        private LayerMask layerMask;

        public event EventHandler<bool> Readied;
        public event EventHandler Attacked;
        public event EventHandler Reloaded;

        private InventoryInstance inventory;
        private readonly RaycastHit[] hits = new RaycastHit[1];

        private void OnValidate()
        {
            if (damageSource == null)
            {
                damageSource = GetComponent<DamageSource>();
            }
        }

        public void OnEquip(InventoryInstance inventory)
        {
            this.inventory = inventory;
        }

        public void OnUnequip() { }

        private void Start()
        {
            if (projectileOrigin == null)
            {
                projectileOrigin = transform;
            }

            var d = Disposable.CreateBuilder();

            ready
                .AsObservable()
                .Subscribe(Ready)
                .AddTo(ref d);

            fire
                .AsObservable()
                .CombineLatest(ready.AsObservable(), (ready, fire) => ready && fire)
                .WhereTrue()
                .AsUnitObservable()
                .Subscribe(_ => Fire())
                .AddTo(ref d);

            reload
                .AsObservable()
                .WhereTrue()
                .Subscribe(_ => Reload())
                .AddTo(ref d);

            d.RegisterTo(destroyCancellationToken);
        }

        private void Ready(bool isReady)
        {
            Readied?.Invoke(this, isReady);
        }

        private void Fire()
        {
            var count = Physics.RaycastNonAlloc(
                projectileOrigin.position,
                projectileOrigin.forward,
                hits,
                projectileLength,
                layerMask
            );

            if (count > 0)
            {
                damageSource.ApplyDamage(hits[0].collider);
            }

            Attacked?.Invoke(this, EventArgs.Empty);
        }

        private void Reload()
        {
            Reloaded?.Invoke(this, EventArgs.Empty);
            Debug.Log("rewowd");
        }

        public void ApplyDamage(int amount, IDamageable target)
        {
            damageSource.ApplyDamage(amount, target);
        }

        private void OnDrawGizmos()
        {
            Gizmos.color = Color.red;
            Gizmos.DrawRay(projectileOrigin.position, projectileOrigin.forward * projectileLength);
        }
    }
}
