#pragma once

#include "GUI/DeepPluckEditorComponents.h"
#include "GUI/DeepPluckStandaloneKeyboard.h"
#include "PluginProcessor.h"

#include <juce_gui_basics/juce_gui_basics.h>

class DeepPluckAudioProcessorEditor final : public juce::AudioProcessorEditor,
                                           private juce::Timer
{
public:
    explicit DeepPluckAudioProcessorEditor (DeepPluckAudioProcessor& processor);
    DeepPluckAudioProcessorEditor (
        DeepPluckAudioProcessor& processor,
        std::shared_ptr<deeppluck::gui::DeepPluckGuiPreferences> preferences);
    DeepPluckAudioProcessorEditor (
        DeepPluckAudioProcessor& processor,
        std::shared_ptr<deeppluck::gui::DeepPluckGuiPreferences> preferences,
        juce::MidiKeyboardState::Listener* injectedStandaloneMidiListener);
    ~DeepPluckAudioProcessorEditor() override;

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

    void showPage (deeppluck::gui::Page page);
    [[nodiscard]] deeppluck::gui::Page getCurrentPage() const noexcept;
    [[nodiscard]] bool isPageVisible (deeppluck::gui::Page page) const noexcept;
    [[nodiscard]] bool isModulationNavigationEnabled() const noexcept;
    [[nodiscard]] bool isEffectsNavigationEnabled() const noexcept;
    [[nodiscard]] int getAttachmentCount() const noexcept;
    [[nodiscard]] bool isOscillatorRowVisible() const noexcept;
    [[nodiscard]] bool isWelcomeVisible() const noexcept;
    [[nodiscard]] bool hasStandaloneKeyboard() const noexcept;
    [[nodiscard]] juce::Rectangle<int> getStandaloneKeyboardPanelBounds() const noexcept;
    [[nodiscard]] juce::Rectangle<int> getStandaloneKeyboardBounds() const noexcept;
    [[nodiscard]] int getStandaloneKeyboardLowestVisibleKey() const noexcept;
    [[nodiscard]] bool isStandaloneOctaveDownEnabled() const noexcept;
    [[nodiscard]] bool isStandaloneOctaveUpEnabled() const noexcept;
    [[nodiscard]] bool standaloneKeyboardWantsKeyboardFocus() const noexcept;
    void standaloneOctaveDownForTests();
    void standaloneOctaveUpForTests();
    void standaloneNoteOnForTests (int midiNoteNumber, float velocity);
    void standaloneNoteOffForTests (int midiNoteNumber, float velocity = 0.0f);
    [[nodiscard]] bool isStandaloneNoteOnForTests (int midiNoteNumber) const noexcept;
    [[nodiscard]] std::array<float, 2> getDisplayedMeterLevels() const noexcept;
    void refreshForTests();
    void refreshMeterForTests();

private:
    void timerCallback() override;

    DeepPluckAudioProcessor& audioProcessor;
    deeppluck::gui::DeepPluckLookAndFeel lookAndFeel;
    std::shared_ptr<deeppluck::gui::DeepPluckGuiPreferences> preferences;
    deeppluck::gui::DeepPluckTooltipWindow tooltipWindow;
    deeppluck::gui::HeaderComponent header;
    deeppluck::gui::OscillatorRowComponent oscillatorRow;
    deeppluck::gui::FinalPageNavigationComponent navigation;
    deeppluck::gui::MainPageComponent mainPage;
    deeppluck::gui::ModulationPageComponent modulationPage;
    deeppluck::gui::EffectsPageComponent effectsPage;
    deeppluck::gui::SettingsPageComponent settingsPage;
    deeppluck::gui::FooterComponent footer;
    deeppluck::gui::WelcomeOverlayComponent welcome;
    std::unique_ptr<deeppluck::gui::DeepPluckStandaloneKeyboardPanel> standaloneKeyboard;
    deeppluck::gui::Page currentPage = deeppluck::gui::Page::main;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DeepPluckAudioProcessorEditor)
};
