#pragma once
#include <juce_audio_processors/juce_audio_processors.h>
#include <juce_gui_basics/juce_gui_basics.h>
#include <juce_dsp/juce_dsp.h>
#include "PluginProcessor.h"
#include <vector>

class KnobLookAndFeel : public juce::LookAndFeel_V4 {
public:
    void drawRotarySlider(juce::Graphics& g, int x, int y, int width, int height,
                          float sliderPos, float rotaryStartAngle,
                          float rotaryEndAngle, juce::Slider& slider) override;
};

class ComboBoxLookAndFeel : public juce::LookAndFeel_V4 {
public:
    void drawComboBox(juce::Graphics& g, int width, int height,
                      bool isButtonDown, int buttonX, int buttonY,
                      int buttonW, int buttonH, juce::ComboBox& box) override;
    void drawPopupMenuItem(juce::Graphics& g, const juce::Rectangle<int>& area,
                           bool isSeparator, bool isActive, bool isHighlighted,
                           bool isTicked, bool hasSubMenu, const juce::String& text,
                           const juce::String& shortcutKeyText,
                           const juce::Drawable* icon, const juce::Colour* textColour) override;
};

class VuMeter : public juce::Component, public juce::Timer {
public:
    explicit VuMeter(ChromaFlockProcessor& p) : processor(p) { startTimerHz(30); }
    void paint(juce::Graphics& g) override;
    void timerCallback() override { repaint(); }
private:
    ChromaFlockProcessor& processor;
};

class WaveformDisplay : public juce::Component, public juce::Timer {
public:
    explicit WaveformDisplay(ChromaFlockProcessor& p) : processor(p) { startTimerHz(30); }
    void paint(juce::Graphics& g) override;
    void timerCallback() override { repaint(); }
private:
    ChromaFlockProcessor& processor;
};

class SpectrumAnalyzer : public juce::Component, public juce::Timer {
public:
    explicit SpectrumAnalyzer(ChromaFlockProcessor& p) : processor(p) {
        fft = std::make_unique<juce::dsp::FFT>(ChromaFlockProcessor::fftOrder);
        startTimerHz(30);
    }
    void paint(juce::Graphics& g) override;
    void timerCallback() override { repaint(); }
private:
    ChromaFlockProcessor& processor;
    std::unique_ptr<juce::dsp::FFT> fft;
};

class PianoRollComponent : public juce::Component, public juce::Timer {
public:
    explicit PianoRollComponent(ChromaFlockProcessor& p) : processor(p) { startTimerHz(30); }
    void paint(juce::Graphics& g) override;
    void timerCallback() override { repaint(); }
    void mouseDown(const juce::MouseEvent& e) override;
    void mouseUp(const juce::MouseEvent& e) override;
    void mouseDrag(const juce::MouseEvent& e) override;

private:
    ChromaFlockProcessor& processor;

    static constexpr int firstMidiNote = 48; // C3
    static constexpr int numKeys = 49;       // C3..C7

    int whiteKeyWidth = 54;
    int whiteKeyHeight = 130;
    int blackKeyWidth = 35;
    int blackKeyHeight = 80;
    int pitchBendWidth = 40;

    int midiNoteForKey(int index) const;
    bool isBlackKey(int midiNote) const;
    int keyAtPosition(juce::Point<int> pos) const;
    void triggerNote(int note, bool on);

    int lastTriggeredNote = -1;
    int currentPitchBend = 64; // 0..127, 64 = center
};

class MainContentComponent : public juce::Component {
public:
    explicit MainContentComponent(ChromaFlockProcessor& p);
    void paint(juce::Graphics& g) override;
    void resized() override;

    std::function<void(float)> onScaleChanged;

private:
    ChromaFlockProcessor& processorRef;
    KnobLookAndFeel knobLaf;
    ComboBoxLookAndFeel comboLaf;
    juce::Image bgImage;
    bool bgImageLoaded = false;
    juce::Image logoImage;
    bool logoLoaded = false;

    VuMeter vuMeter;
    WaveformDisplay waveformDisplay;
    SpectrumAnalyzer spectrumAnalyzer;
    PianoRollComponent pianoRoll;

    juce::Label osc1Label, osc2Label, filterLabel, envLabel, fEnvLabel, globalLabel;
    juce::Label fxLabel, lfoLabel, fx2Label;
    juce::Label scaleLabel;

    juce::ComboBox osc1WaveBox;
    juce::Slider osc1OctKnob, osc1SemiKnob, osc1FineKnob, osc1LevelKnob;

    juce::ComboBox osc2WaveBox;
    juce::Slider osc2OctKnob, osc2SemiKnob, osc2FineKnob, osc2LevelKnob, phaseOffsetKnob;

    juce::ComboBox filterTypeBox;
    juce::Slider filterCutoffKnob, filterResKnob, filterEnvAmtKnob, keyTrackKnob;

    juce::Slider envAttackKnob, envDecayKnob, envSustainKnob, envReleaseKnob;
    juce::Slider fEnvAttackKnob, fEnvDecayKnob, fEnvSustainKnob, fEnvReleaseKnob;

    juce::Slider panKnob, driveKnob, masterKnob, pbRangeKnob;

    // FX controls
    juce::ComboBox distTypeBox;
    juce::Slider distAmountKnob, distMixKnob;
    juce::Slider compThresholdKnob, compRatioKnob, compAttackKnob, compReleaseKnob, compMakeupKnob, compMixKnob;
    juce::Slider autoPanRateKnob, autoPanDepthKnob;

    // LFO controls
    juce::Slider lfo1RateKnob, lfo1DepthKnob;
    juce::ComboBox lfo1ShapeBox, lfo1DestBox;
    juce::Slider lfo2RateKnob, lfo2DepthKnob;
    juce::ComboBox lfo2ShapeBox, lfo2DestBox;

    // FX2 controls
    juce::Slider delayTimeKnob, delayFbKnob, delayMixKnob;
    juce::ComboBox delayPingPongBox;
    juce::Slider delaySpreadKnob;
    juce::Slider reverbSizeKnob, reverbDampKnob, reverbMixKnob;

    // Preset menu
    juce::TextButton presetButton{"PRESET"};

    juce::ComboBox uiScaleBox;

    using SliderAttachment = juce::AudioProcessorValueTreeState::SliderAttachment;
    using ComboBoxAttachment = juce::AudioProcessorValueTreeState::ComboBoxAttachment;

    std::unique_ptr<SliderAttachment> osc1OctAttach, osc1SemiAttach, osc1FineAttach, osc1LevelAttach;
    std::unique_ptr<SliderAttachment> osc2OctAttach, osc2SemiAttach, osc2FineAttach, osc2LevelAttach, phaseOffsetAttach;
    std::unique_ptr<ComboBoxAttachment> osc1WaveAttach, osc2WaveAttach, filterTypeAttach;
    std::unique_ptr<SliderAttachment> filterCutoffAttach, filterResAttach, filterEnvAmtAttach, keyTrackAttach;
    std::unique_ptr<SliderAttachment> envAttackAttach, envDecayAttach, envSustainAttach, envReleaseAttach;
    std::unique_ptr<SliderAttachment> fEnvAttackAttach, fEnvDecayAttach, fEnvSustainAttach, fEnvReleaseAttach;
    std::unique_ptr<SliderAttachment> panAttach, driveAttach, masterAttach, pbRangeAttach;

    // FX attachments
    std::unique_ptr<ComboBoxAttachment> distTypeAttach;
    std::unique_ptr<SliderAttachment> distAmountAttach, distMixAttach;
    std::unique_ptr<SliderAttachment> compThresholdAttach, compRatioAttach, compAttackAttach;
    std::unique_ptr<SliderAttachment> compReleaseAttach, compMakeupAttach, compMixAttach;
    std::unique_ptr<SliderAttachment> autoPanRateAttach, autoPanDepthAttach;

    // LFO attachments
    std::unique_ptr<SliderAttachment> lfo1RateAttach, lfo1DepthAttach;
    std::unique_ptr<ComboBoxAttachment> lfo1ShapeAttach, lfo1DestAttach;
    std::unique_ptr<SliderAttachment> lfo2RateAttach, lfo2DepthAttach;
    std::unique_ptr<ComboBoxAttachment> lfo2ShapeAttach, lfo2DestAttach;

    // FX2 attachments
    std::unique_ptr<SliderAttachment> delayTimeAttach, delayFbAttach, delayMixAttach;
    std::unique_ptr<ComboBoxAttachment> delayPingPongAttach;
    std::unique_ptr<SliderAttachment> delaySpreadAttach;
    std::unique_ptr<SliderAttachment> reverbSizeAttach, reverbDampAttach, reverbMixAttach;

    void setupLabel(juce::Label& label, const juce::String& text);
    void setupKnob(juce::Slider& knob, const juce::String& name);
    void setupCombo(juce::ComboBox& combo);
    void showPresetMenu();

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainContentComponent)
};

class ChromaFlockEditor : public juce::AudioProcessorEditor {
public:
    ChromaFlockEditor(ChromaFlockProcessor& p);
    ~ChromaFlockEditor() override;

    void paint(juce::Graphics&) override;
    void resized() override;
    void setUIScale(float newScale);

private:
    MainContentComponent content;
    float currentScale = 1.0f;
    static constexpr int baseWidth = 1660;
    static constexpr int baseHeight = 1182;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ChromaFlockEditor)
};
