#pragma once

using namespace rack;

struct AutoParamQuantity : ParamQuantity {
  std::string getDisplayValueString() override {
    std::string disp = Quantity::getDisplayValueString();
    return disp == "0" ? "Auto" : disp;
  }
};

static std::vector<std::string> polyChannelLabels(bool includeAuto) {
  std::vector<std::string> labels;
  if (includeAuto) {
    labels.push_back("Auto");
  }
  for (int i = 1; i <= 16; i++) {
    labels.push_back(std::to_string(i));
  }
  return labels;
}

struct ComputerscarePolyModule : Module {
  int polyChannels = 16;
  int polyChannelsKnobSetting = 0;
  int counterPeriod = 64;
  int counter = counterPeriod + 1;

  virtual void checkCounter() {
    counter++;
    if (counter > counterPeriod) {
      checkPoly();
      counter = 0;
    }
  }

  virtual void checkPoly() {};
};

struct TinyChannelsSnapKnob : ComputerscareRoundKnob {
  std::shared_ptr<Svg> manualChannelsSetSvg = APP->window->loadSvg(
      asset::plugin(pluginInstance,
                    "res/components/computerscare-channels-empty-knob.svg"));
  std::shared_ptr<Svg> autoChannelsSvg = APP->window->loadSvg(asset::plugin(
      pluginInstance,
      "res/components/computerscare-channels-empty-knob-auto-mode.svg"));
  int prevSetting = -1;
  int paramId = -1;
  int previewChannels = 16;

  ComputerscarePolyModule* module;

  TinyChannelsSnapKnob() {
    setSvg(APP->window->loadSvg(
        asset::plugin(pluginInstance,
                      "res/components/computerscare-channels-empty-knob.svg")));
    shadow->opacity = 0.f;
    snap = true;
    ComputerscareRoundKnob();
  }
  void draw(const DrawArgs& args) override {
    if (module) {
      int currentSetting = module->params[paramId].getValue();
      ;
      if (currentSetting != prevSetting) {
        setSvg(currentSetting == 0 ? autoChannelsSvg : manualChannelsSetSvg);
        prevSetting = currentSetting;
      }
    } else {
      setSvg(manualChannelsSetSvg);
      float angle =
          math::rescale((float)previewChannels, 1.f, 16.f, minAngle, maxAngle);
      math::Vec center = sw->box.getCenter();
      tw->identity();
      tw->translate(center);
      tw->rotate(angle);
      tw->translate(center.neg());
      fb->setDirty();
    }
    ComputerscareRoundKnob::draw(args);
  }
};

struct PolyChannelsDisplay : SmallLetterDisplay {
  ComputerscarePolyModule* module;
  bool controlled = false;
  int prevChannels = -1;
  int paramId = -1;
  int previewChannels = 16;

  PolyChannelsDisplay(math::Vec pos) {
    box.pos = pos;
    fontSize = 14;
    letterSpacing = 1.f;
    textAlign = 18;
    textColor = BLACK;
    breakRowWidth = 20;
    SmallLetterDisplay();
  };
  void draw(const DrawArgs& args) {
    if (module) {
      int newChannels = module->polyChannels;
      if (newChannels != prevChannels) {
        std::string str = std::to_string(newChannels);
        value = str;
        prevChannels = newChannels;
      }

    } else {
      value = std::to_string(previewChannels);
    }
    SmallLetterDisplay::draw(args);
  }
};
struct PolyOutputChannelsWidget : Widget {
  ComputerscarePolyModule* module;
  PolyChannelsDisplay* channelCountDisplay;
  TinyChannelsSnapKnob* channelsKnob;
  PolyOutputChannelsWidget(math::Vec pos, ComputerscarePolyModule* mod,
                           int paramId, int previewChannels = -1) {
    module = mod;

    channelsKnob =
        createParam<TinyChannelsSnapKnob>(pos.plus(Vec(7, 3)), module, paramId);
    channelsKnob->module = module;
    channelsKnob->paramId = paramId;
    channelsKnob->previewChannels =
        previewChannels > 0 ? previewChannels : (int)(random::u32() % 16) + 1;

    channelCountDisplay = new PolyChannelsDisplay(pos);

    channelCountDisplay->module = module;
    channelCountDisplay->previewChannels = channelsKnob->previewChannels;

    addChild(channelsKnob);
    addChild(channelCountDisplay);
  }
};
