// editor_paint_deck.cpp — the DECKS band's painter: the fenced control groups (AMP
// ENVELOPE / PITCH / PITCH ENV / VOICE / MASTER), their captions, the compact caption and
// row toggles, and the radial knobs with the label<->value swap on hover/drag.
// Windows-only; the deck's cell geometry is the pure knob_deck layout.

#include "shell/instrument/reasampler_editor.h"

#ifdef _WIN32

#include <string>
#include <vector>

#include "core/instrument/ui/knob_deck.h"       // deck layout + kDeckKnobSize
#include "shell/instrument/editor_internal.h"   // kit adapters + knob face + DeckGroup ids
#include "shell/instrument/reasampler_processor.h"

namespace reasampler::vst {

using namespace reasampler::ui;              // kit vocabulary
using namespace reasampler::instrument::ui;  // deck geometry

void ReaSamplerEditor::paintDeck(LICE_IBitmap* bmp, const FaceLayout& fl) {
    const Rect& deckArea = fl.bands.decks;
    if (deckArea.width <= 0 || deckArea.height <= 0) return;
    const DeckLayout dl = layoutDeck(fl.deckDescs, deckArea.x, deckArea.y, deckArea.width);
    const PlaySeconds& play = params_.play;
    const bool isMono = (voiceMode_ == VoiceMode::Mono);
    const LICE_pixel hairline = toLice(roleColor(Role::LineHairline));

    // One compact-toggle draw (the Mono/Stereo segment grammar at Micro scale). Disabled
    // segments draw inert so the dependency (Retrig|Legato needs Mono) reads at a glance.
    const auto drawToggle = [&](const DeckToggleLayout& t, const char* s0, const char* s1,
                                bool seg1Active, bool disabled) {
        const bool hov = !disabled && isHovered(HoverKind::kControl, t.id);
        const InteractionState st0 =
            disabled ? InteractionState::Disabled
                     : (!seg1Active ? InteractionState::Active
                                    : (hov ? InteractionState::Hover : InteractionState::Rest));
        const InteractionState st1 =
            disabled ? InteractionState::Disabled
                     : (seg1Active ? InteractionState::Active
                                   : (hov ? InteractionState::Hover : InteractionState::Rest));
        fillSurface(bmp, toKitBox(t.seg0), Role::BgCell, st0);
        fillSurface(bmp, toKitBox(t.seg1), Role::BgCell, st1);
        kitTextCentered(bmp, t.seg0, s0, Font::Micro,
                        disabled ? Role::TextDim
                                 : (!seg1Active ? Role::BgBase : Role::TextPrimary));
        kitTextCentered(bmp, t.seg1, s1, Font::Micro,
                        disabled ? Role::TextDim
                                 : (seg1Active ? Role::BgBase : Role::TextPrimary));
    };

    // The knob's short name label (swapped for the live value during hover/drag — no third
    // line, no permanent value clutter).
    const auto knobName = [](ParamControl c) -> const char* {
        switch (c) {
            case ParamControl::kAttack:         return "Attack";
            case ParamControl::kHold:           return "Hold";
            case ParamControl::kDecay:          return "Decay";
            case ParamControl::kSustain:        return "Sustain";
            case ParamControl::kRelease:        return "Release";
            case ParamControl::kTrigFadeIn:     return "Fade In";
            case ParamControl::kTrigLength:     return "Len %";
            case ParamControl::kTrigFadeOut:    return "Fade Out";
            case ParamControl::kKeyTrack:       return "Key Trk";
            case ParamControl::kPitchEnvAttack: return "P.Att";
            case ParamControl::kPitchEnvDecay:  return "P.Dec";
            case ParamControl::kPitchEnvDepth:  return "P.Depth";
            case ParamControl::kVoiceCount:     return "Voices";
            case ParamControl::kMasterGain:     return "Gain";
            default:                            return "";
        }
    };

    for (const DeckGroupLayout& g : dl.groups) {
        // The fence: a bg/panel box with a hairline border, caption micro-caps left.
        fillSurface(bmp, toKitBox(g.box), Role::BgPanel, InteractionState::Rest);
        LICE_DrawRect(bmp, g.box.x, g.box.y, g.box.width - 1, g.box.height - 1,
                      hairline, 1.0f, 0);
        const char* caption = "";
        switch (g.id) {
            case kGroupAmpEnv:   caption = "AMP ENVELOPE"; break;
            case kGroupPitch:    caption = "PITCH"; break;
            case kGroupPitchEnv: caption = "PITCH ENV"; break;
            case kGroupVoice:    caption = "VOICE"; break;
            case kGroupMaster:   caption = "MASTER"; break;
            default: break;
        }
        kitText(bmp, g.caption, caption, Font::Micro, Role::TextDim);

        // The compact caption toggle (right-anchored in the caption row, never full-width).
        if (g.captionToggle.id >= 0) {
            switch (static_cast<ParamControl>(g.captionToggle.id)) {
                case ParamControl::kPlayMode:
                    drawToggle(g.captionToggle, "Gate", "Trigger",
                               play.playMode == PlayMode::Trigger, false);
                    break;
                case ParamControl::kPitchEngine:
                    drawToggle(g.captionToggle, "Varisp", "Presrv",
                               play.pitchEngine == PitchEngine::Preserve, false);
                    break;
                case ParamControl::kPitchEnvEnable:
                    drawToggle(g.captionToggle, "Off", "On", play.pitchEnv.enabled, false);
                    break;
                case ParamControl::kVoiceMode:
                    drawToggle(g.captionToggle, "Poly", "Mono", isMono, false);
                    break;
                default: break;
            }
        }
        // The row toggle (VOICE group's Retrig|Legato) — live only in Mono.
        if (g.rowToggle.id >= 0) {
            drawToggle(g.rowToggle, "Retrig", "Legato",
                       monoTrigger_ == MonoTrigger::Legato, !isMono);
        }

        // The knobs. PITCH ENV knobs draw Disabled (not hidden) while the envelope is off —
        // stable geometry.
        for (const DeckCellLayout& c : g.cells) {
            if (c.id < 0) continue;  // reserved blank cell (the Trigger face's two spares)
            const bool disabled = (g.id == kGroupPitchEnv && !play.pitchEnv.enabled);
            const bool dragging = (drag_ == DragKind::kDeckKnob && dragParamId_ == c.id);
            const bool hov = !disabled && isHovered(HoverKind::kControl, c.id);
            const InteractionState st =
                disabled ? InteractionState::Disabled
                         : (dragging ? InteractionState::Dragging
                                     : (hov ? InteractionState::Hover : InteractionState::Rest));
            drawKnobFace(bmp, c.knob, deckControlNorm(c.id), st);
            const std::string label = (dragging || hov)
                ? deckValueLabel(c.id)
                : std::string(knobName(static_cast<ParamControl>(c.id)));
            kitTextCentered(bmp, c.label, label.c_str(), Font::Micro, Role::TextDim);
        }
    }
}

}  // namespace reasampler::vst

#endif  // _WIN32
