#pragma once

#include "DeepPluckGuiSupport.h"

#include <juce_audio_utils/juce_audio_utils.h>

namespace deeppluck::gui
{
class DeepPluckStandaloneKeyboardPanel final : public juce::Component
{
public:
    static constexpr int midiChannel = 1;
    static constexpr int minimumLowestVisibleKey = 0;
    static constexpr int maximumLowestVisibleKey = 60;
    static constexpr int initialLowestVisibleKey = 36;
    static constexpr int octaveStep = 12;

    explicit DeepPluckStandaloneKeyboardPanel (
        juce::MidiKeyboardState::Listener* midiListener);
    ~DeepPluckStandaloneKeyboardPanel() override;

    void paint (juce::Graphics& graphics) override;
    void resized() override;

    void disconnect();
    void releaseAllNotes();

    [[nodiscard]] int getLowestVisibleKey() const noexcept;
    [[nodiscard]] bool isOctaveDownEnabled() const noexcept;
    [[nodiscard]] bool isOctaveUpEnabled() const noexcept;
    [[nodiscard]] bool keyboardWantsKeyboardFocus() const noexcept;
    [[nodiscard]] juce::Rectangle<int> getKeyboardBounds() const noexcept;
    [[nodiscard]] int getKeyboardRangeStart() const noexcept;
    [[nodiscard]] int getKeyboardRangeEnd() const noexcept;
    [[nodiscard]] int getKeyboardMidiChannel() const noexcept;

    void octaveDownForTests();
    void octaveUpForTests();
    void noteOnForTests (int midiNoteNumber, float velocity);
    void noteOffForTests (int midiNoteNumber, float velocity = 0.0f);
    [[nodiscard]] bool isNoteOnForTests (int midiNoteNumber) const noexcept;

private:
    class MouseOnlyKeyboardComponent final : public juce::MidiKeyboardComponent
    {
    public:
        explicit MouseOnlyKeyboardComponent (juce::MidiKeyboardState& state)
            : juce::MidiKeyboardComponent (
                  state, juce::KeyboardComponentBase::horizontalKeyboard)
        {
        }

        void mouseWheelMove (const juce::MouseEvent& event,
                             const juce::MouseWheelDetails& wheel) override
        {
            juce::ignoreUnused (event, wheel);
        }
    };

    void shiftOctave (int semitones);
    void updateOctaveButtons();

    juce::MidiKeyboardState keyboardState;
    MouseOnlyKeyboardComponent keyboard { keyboardState };
    juce::TextButton octaveDown { "Oct -" };
    juce::TextButton octaveUp { "Oct +" };
    juce::MidiKeyboardState::Listener* listener = nullptr;
    int lowestVisibleKey = initialLowestVisibleKey;
    bool connected = false;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DeepPluckStandaloneKeyboardPanel)
};
}
