// SPDX-FileCopyrightText: 2026 0064ff
// SPDX-License-Identifier: MIT-0

#pragma once
#include <JuceHeader.h>

class MyLookAndFeel : public juce::LookAndFeel_V4
{
public:
    //==============================================================================

    MyLookAndFeel() = default;

    //==============================================================================

    void drawLinearSlider(juce::Graphics& g,
                          int /*x*/, int /*y*/,
                          int /*width*/, int /*height*/,
                          float sliderPos,
                          float /*minSliderPos*/, float /*maxSliderPos*/,
                          juce::Slider::SliderStyle /*style*/,
                          juce::Slider& s) override
    {
        // get properties of slider
        bool isBool = s.getProperties().getWithDefault("isBool", false);
        bool isBipolar = s.getProperties().getWithDefault("isBipolar", false);

        float const sliderWidth = static_cast<float>(s.getWidth());
        float const sliderHeight = static_cast<float>(s.getHeight());

        if (sliderWidth != sliderHeight) // slider bars
        {
            float const cornerSizeDivisor = 3.0f;

            // l = long, s = short
            float const lSize = sliderWidth > sliderHeight ? sliderWidth : sliderHeight;
            float const sSize = sliderWidth < sliderHeight ? sliderWidth : sliderHeight;
            float const lPos = 0.0f;
            float const sPos = 0.0f;
            float const cornerSize = sSize / cornerSizeDivisor;

            float const thumbPadding = sSize / 8.0f;
            float const thumbLSizeRaw = lSize / 8.0f;
            float const thumbLSize = thumbLSizeRaw - thumbPadding * 2.0f;
            float const thumbSSize = sSize - thumbPadding * 2.0f;
            float const thumbPosRatio = sliderPos / lSize;
            float const thumbLPos = thumbPosRatio * (lSize - thumbLSizeRaw) + thumbPadding;
            float const thumbSPos = sPos + thumbPadding;
            float const thumbCornerSize = thumbSSize / cornerSizeDivisor;

            float sliderEffectiveXPos, sliderEffectiveYPos;
            float sliderEffectiveWidth, sliderEffectiveHeight;
            float sliderThumbEffectiveXPos, sliderThumbEffectiveYPos;
            float sliderThumbEffectiveWidth, sliderThumbEffectiveHeight;
            if (sliderWidth > sliderHeight) // horizontal sliders
            {
                sliderEffectiveXPos = lPos;
                sliderEffectiveYPos = sPos;
                sliderEffectiveWidth = lSize;
                sliderEffectiveHeight = sSize;
                sliderThumbEffectiveXPos = thumbLPos;
                sliderThumbEffectiveYPos = thumbSPos;
                sliderThumbEffectiveWidth = thumbLSize;
                sliderThumbEffectiveHeight = thumbSSize;
            }
            else // vertical sliders
            {
                sliderEffectiveXPos = sPos;
                sliderEffectiveYPos = lPos;
                sliderEffectiveWidth = sSize;
                sliderEffectiveHeight = lSize;
                sliderThumbEffectiveXPos = thumbSPos;
                sliderThumbEffectiveYPos = thumbLPos;
                sliderThumbEffectiveWidth = thumbSSize;
                sliderThumbEffectiveHeight = thumbLSize;
            }

            g.setColour(sliderColor);
            g.fillRoundedRectangle(sliderEffectiveXPos, sliderEffectiveYPos,
                                   sliderEffectiveWidth, sliderEffectiveHeight,
                                   cornerSize);

            g.setColour(sliderThumbColor);
            g.fillRoundedRectangle(sliderThumbEffectiveXPos, sliderThumbEffectiveYPos,
                                   sliderThumbEffectiveWidth, sliderThumbEffectiveHeight,
                                   thumbCornerSize);
        }
        else // sliderWidth == sliderHeight (slider circles)
        {
            float const cornerSizeDivisor = 2.25f;

            float const sideLength = sliderWidth;
            float const sliderSquarePos = 0.0f;
            float const cornerSize = sideLength / cornerSizeDivisor;

            float const thumbPadding = sideLength / 16.0f;
            float const thumbSideLengthRaw = sideLength;
            float const thumbSideLength = thumbSideLengthRaw - thumbPadding * 2.0f;
            float const thumbPosRatio = 1.0f - sliderPos / sideLength;
            float const thumbPos = sliderSquarePos + thumbPadding;
            float const thumbCornerSize = thumbSideLength / cornerSizeDivisor;

            g.setColour(sliderColor);
            g.fillRoundedRectangle(sliderSquarePos, sliderSquarePos,
                                   sideLength, sideLength,
                                   cornerSize);

            juce::Rectangle<float> visibleArea(sliderSquarePos, sliderSquarePos, sideLength, sideLength);
            g.setColour(sliderThumbColor);

            if (isBool || isBipolar) // two-color sliders for bool or bipolar sliders
            {
                if (thumbPosRatio >= 0.5f) // upper half fills from bottom
                {
                    float const thumbPosRatioNormAbove = (thumbPosRatio-0.5f) * 2.0f;
                    visibleArea = visibleArea.removeFromBottom(sideLength * thumbPosRatioNormAbove);
                }
                else // lower half fills from top with inverted color
                {
                    g.setColour(sliderThumbColorInv);
                    float const thumbPosRatioNormBelow = thumbPosRatio * 2.0f;
                    visibleArea = visibleArea.removeFromTop(sideLength * (1.0f-thumbPosRatioNormBelow));
                }
            }
            else // single-color sliders fill from bottom for general sliders
            {
                visibleArea = visibleArea.removeFromBottom(sideLength*thumbPosRatio);
            }

            // prevent upcoming clipping from leaking into any other drawing
            juce::Graphics::ScopedSaveState saveState(g);

            // need to use a path because reduceclipregion doesn't take a float rectangle
            juce::Path clipRegion;
            clipRegion.addRectangle(visibleArea);
            g.reduceClipRegion(clipRegion, juce::AffineTransform());

            g.fillRoundedRectangle(thumbPos, thumbPos,
                                   thumbSideLength, thumbSideLength,
                                   thumbCornerSize);
        }
    }

    //==============================================================================

    juce::Colour sliderColor, sliderThumbColor, sliderThumbColorInv;
};
