// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.Objects.Drawables;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play;

namespace osu.Game.Rulesets.Taiko.UI
{
    internal partial class DrumSamplePlayer : CompositeDrawable, IKeyBindingHandler<TaikoAction>
    {
        private DrumSampleTriggerSource leftCentreTrigger = null!;
        private DrumSampleTriggerSource rightCentreTrigger = null!;
        private DrumSampleTriggerSource leftRimTrigger = null!;
        private DrumSampleTriggerSource rightRimTrigger = null!;
        private DrumSampleTriggerSource strongCentreTrigger = null!;
        private DrumSampleTriggerSource strongRimTrigger = null!;

        private double lastHitTime;
        private TaikoAction? lastAction;

        [BackgroundDependencyLoader]
        private void load(Playfield playfield)
        {
            var hitObjectContainer = playfield.HitObjectContainer;
            InternalChildren = new Drawable[]
            {
                leftCentreTrigger = CreateTriggerSource(hitObjectContainer, SampleBalance.Left),
                rightCentreTrigger = CreateTriggerSource(hitObjectContainer, SampleBalance.Right),
                leftRimTrigger = CreateTriggerSource(hitObjectContainer, SampleBalance.Left),
                rightRimTrigger = CreateTriggerSource(hitObjectContainer, SampleBalance.Right),
                strongCentreTrigger = CreateTriggerSource(hitObjectContainer, SampleBalance.Centre),
                strongRimTrigger = CreateTriggerSource(hitObjectContainer, SampleBalance.Centre)
            };
        }

        protected virtual DrumSampleTriggerSource CreateTriggerSource(HitObjectContainer hitObjectContainer, SampleBalance balance)
            => new DrumSampleTriggerSource(hitObjectContainer);

        public bool OnPressed(KeyBindingPressEvent<TaikoAction> e)
        {
            if ((Clock as IGameplayClock)?.IsRewinding == true)
                return false;

            HitType hitType;

            DrumSampleTriggerSource triggerSource;

            bool strong = checkStrongValidity(e.Action, lastAction, Time.Current - lastHitTime);

            switch (e.Action)
            {
                case TaikoAction.LeftCentre:
                    hitType = HitType.Centre;
                    triggerSource = strong ? strongCentreTrigger : leftCentreTrigger;
                    break;

                case TaikoAction.RightCentre:
                    hitType = HitType.Centre;
                    triggerSource = strong ? strongCentreTrigger : rightCentreTrigger;
                    break;

                case TaikoAction.LeftRim:
                    hitType = HitType.Rim;
                    triggerSource = strong ? strongRimTrigger : leftRimTrigger;
                    break;

                case TaikoAction.RightRim:
                    hitType = HitType.Rim;
                    triggerSource = strong ? strongRimTrigger : rightRimTrigger;
                    break;

                default:
                    return false;
            }

            if (strong)
            {
                switch (hitType)
                {
                    case HitType.Centre:
                        flushCenterTriggerSources();
                        break;

                    case HitType.Rim:
                        flushRimTriggerSources();
                        break;
                }
            }

            Play(triggerSource, hitType, strong);

            lastHitTime = Time.Current;
            lastAction = e.Action;

            return false;
        }

        protected virtual void Play(DrumSampleTriggerSource triggerSource, HitType hitType, bool strong) =>
            triggerSource.Play(hitType, strong);

        private bool checkStrongValidity(TaikoAction newAction, TaikoAction? lastAction, double timeBetweenActions)
        {
            if (lastAction == null)
                return false;

            if (timeBetweenActions < 0 || timeBetweenActions > DrawableHit.StrongNestedHit.SECOND_HIT_WINDOW)
                return false;

            switch (newAction)
            {
                case TaikoAction.LeftCentre:
                    return lastAction == TaikoAction.RightCentre;

                case TaikoAction.RightCentre:
                    return lastAction == TaikoAction.LeftCentre;

                case TaikoAction.LeftRim:
                    return lastAction == TaikoAction.RightRim;

                case TaikoAction.RightRim:
                    return lastAction == TaikoAction.LeftRim;

                default:
                    return false;
            }
        }

        private void flushCenterTriggerSources()
        {
            leftCentreTrigger.StopAllPlayback();
            rightCentreTrigger.StopAllPlayback();
            strongCentreTrigger.StopAllPlayback();
        }

        private void flushRimTriggerSources()
        {
            leftRimTrigger.StopAllPlayback();
            rightRimTrigger.StopAllPlayback();
            strongRimTrigger.StopAllPlayback();
        }

        public void OnReleased(KeyBindingReleaseEvent<TaikoAction> e)
        {
        }
    }
}