// SPDX-License-Identifier: Unlicense

#include "api.h"

#ifdef SHR3D_SFX_CORE_EXTENSION_V2

#include <stdio.h>

static constexpr f32 default_preset = 0.5f;
static constexpr f32 default_volume = 0.6f;
static constexpr f32 default_threshold = 0.5f;
static constexpr f32 default_power = 0.4f;
static constexpr f32 default_voltage = 0.6f;
static constexpr f32 default_speed = 0.7f;

struct DemoUIInstance final : SfxCoreExtensionV2Instance
{
  f32 preset = default_preset;
  f32 volume = default_volume;
  f32 threshold = default_threshold;
  f32 power = default_power;
  f32 voltage = default_voltage;
  f32 speed = default_speed;

  ProcessBlockResult processBlock(f32** inBlock, f32** /*outBlock*/, const i32 blockSize) override
  {
    for (i32 i = 0; i < blockSize; ++i)
    {
      inBlock[0][i] *= volume * threshold * power;
      inBlock[1][i] *= voltage * speed;
    }
    return ProcessBlockResult::ProcessedInInBlock;
  }

  f32 getParameter(const i32 index) const override
  {
    switch (index)
    {
    case 0:
      return preset;
    case 1:
      return volume;
    case 2:
      return threshold;
    case 3:
      return power;
    case 4:
      return voltage;
    case 5:
      return speed;
    default:
      unreachable();
    }
  }

  void setParameter(const i32 index, const f32 value) override
  {
    switch (index)
    {
    case 0:
      preset = value;
      if (preset < 0.2f)
      {
        volume = 0.2f;
        threshold = 0.1f;
        power = 0.4f;
        voltage = 0.3f;
        speed = 0.5f;
      }
      else if (preset < 0.4f)
      {
        volume = 0.4f;
        threshold = 0.5f;
        power = 0.6f;
        voltage = 0.2f;
        speed = 0.3f;
      }
      else if (preset < 0.6f)
      {
        volume = 0.6f;
        threshold = 0.5f;
        power = 0.4f;
        voltage = 0.6f;
        speed = 0.7f;
      }
      else if (preset < 0.8f)
      {
        volume = 0.8f;
        threshold = 0.7f;
        power = 0.4f;
        voltage = 0.8f;
        speed = 0.5f;
      }
      else
      {
        volume = 1.0f;
        threshold = 1.0f;
        power = 0.8f;
        voltage = 0.7f;
        speed = 0.9f;
      }
      break;
    case 1:
      volume = value;
      break;
    case 2:
      threshold = value;
      break;
    case 3:
      power = value;
      break;
    case 4:
      voltage = value;
      break;
    case 5:
      speed = value;
      break;
    default:
      unreachable();
    }
  }

  void getParameterDisplay(const i32 index, char* text) override
  {
    switch (index)
    {
    case 0:
      if (preset < 0.2f)
        sprintf(text, "very low");
      else if (preset < 0.4f)
        sprintf(text, "low");
      else if (preset < 0.6f)
        sprintf(text, "medium");
      else if (preset < 0.8f)
        sprintf(text, "high");
      else
        sprintf(text, "very high");
      break;
    case 1:
      sprintf(text, "%8.2f", volume);
      break;
    case 2:
      sprintf(text, "%8.1f", threshold * 100.0f);
      break;
    case 3:
      sprintf(text, "%8.1f", 500.0f  + power * 2000.0f);
      break;
    case 4:
      sprintf(text, "%8.3f", 75.0f + voltage * 250.0f);
      break;
    case 5:
      sprintf(text, "%8.3f", 10000.0f - speed * 4000.0f);
      break;
    default:
      unreachable();
    }
  }

  void resetParameter(const i32 index) override
  {
    switch (index)
    {
    case 0:
      setParameter(index, default_preset);
      break;
    case 1:
      setParameter(index, default_volume);
      break;
    case 2:
      setParameter(index, default_threshold);
      break;
    case 3:
      setParameter(index, default_power);
      break;
    case 4:
      setParameter(index, default_voltage);
      break;
    case 5:
      setParameter(index, default_speed);
      break;
    default:
      unreachable();
    }
  }
};

static struct DemoUI final : SfxCoreExtensionV2Base
{
  DemoUI()
  {
    RegisterSfxCoreExtensionV2(u8"DemoUI", this);
  }

  i32 getParameterCount() const override
  {
    return 6;
  }

  const char8_t* getParameterLabel(const i32 index) override
  {
    switch (index)
    {
    case 0:
      return u8"";
    case 1:
      return u8"dB";
    case 2:
      return u8"%";
    case 3:
      return u8"W";
    case 4:
      return u8"V";
    case 5:
      return u8"rpm";
    default:
      unreachable();
    }
  }

  const char8_t* getParameterName(const i32 index) override
  {
    switch (index)
    {
    case 0:
      return u8"Preset";
    case 1:
      return u8"Volume";
    case 2:
      return u8"Threshold";
    case 3:
      return u8"Power";
    case 4:
      return u8"Voltage";
    case 5:
      return u8"Speed";
    default:
      unreachable();
    }
  }

  SfxCoreExtensionV2Instance* getInstance(const i32 instance) override
  {
    static SfxCoreExtensionV2Instance* instances[ExtensionV2MaxInstanceCount];
    assert(instance < ARRAY_SIZE(instances));

    if (instances[instance] == nullptr)
      instances[instance] = new DemoUIInstance;

    return instances[instance];
  }
} demoUI;

#endif // SHR3D_SFX_CORE_EXTENSION_V2
