#include "camera.h"
#include <SDL3/SDL_gamepad.h>
#include <iostream>

/*
  I bought a very cheap ps4 knockoff controller and for some reason
  AXIS_RIGHTX and AXIS_RIGHTY are swapped with the triggers?
  this should be defined as 0 for a working one
 */ 
#define WEIRD_JOYSTICK_BEHAVIOR 1

void Camera::update() {
  float speed = move_speed * (shifted ? 2.0f : 1.0f);
  if(zoom >= 1.0f) {
    speed /= zoom;
  }
  
  if (move_left)   pos.x -= speed;
  if (move_right)  pos.x += speed;
  if (move_up)     pos.y += speed;
  if (move_down)   pos.y -= speed;
}

void Camera::on_key(SDL_Scancode scancode, bool pressed) {
  switch (scancode) {
    case SDL_SCANCODE_W:
    case SDL_SCANCODE_UP:
      move_up = pressed;
      break;
    case SDL_SCANCODE_S:
    case SDL_SCANCODE_DOWN:
      move_down = pressed;
      break;
    case SDL_SCANCODE_A:
    case SDL_SCANCODE_LEFT:
      move_left = pressed;
      break;
    case SDL_SCANCODE_D:
    case SDL_SCANCODE_RIGHT:
      move_right = pressed;
      break;
    case SDL_SCANCODE_LSHIFT:
    case SDL_SCANCODE_RSHIFT:
      shifted = pressed;
      break;
    default:
      break;
  }
}

#ifndef WEIRD_JOYSTICK_BEHAVIOR
#define WEIRD_JOYSTICK_BEHAVIOR 0
#endif
static float normalize_stick(SDL_Gamepad* gamepad, SDL_GamepadAxis axis) {
  if (axis == SDL_GAMEPAD_AXIS_COUNT || axis == SDL_GAMEPAD_AXIS_INVALID)
    return 0.0f;

  float d = static_cast<float>(SDL_GetGamepadAxis(gamepad, axis));

  bool reported_trigger = (axis == SDL_GAMEPAD_AXIS_LEFT_TRIGGER || axis == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER);
  bool really_trigger = (WEIRD_JOYSTICK_BEHAVIOR) ? (axis == SDL_GAMEPAD_AXIS_RIGHTX || axis == SDL_GAMEPAD_AXIS_RIGHTY) : reported_trigger;

  float min = (reported_trigger) ? 0 : SDL_JOYSTICK_AXIS_MIN;
  float max = SDL_JOYSTICK_AXIS_MAX;
  float n = (d - min) / (max - min);

  return really_trigger ? n : ((n - 0.5) * 2.0);
}

void Camera::on_gamepad(SDL_Gamepad* gamepad) {
  if (!gamepad) return;

  float lx = normalize_stick(gamepad, SDL_GAMEPAD_AXIS_LEFTX);
  float ly = normalize_stick(gamepad, SDL_GAMEPAD_AXIS_LEFTY);
  float rx = normalize_stick(gamepad, (WEIRD_JOYSTICK_BEHAVIOR) ? SDL_GAMEPAD_AXIS_LEFT_TRIGGER : SDL_GAMEPAD_AXIS_RIGHTX);

  static uint8_t frame = 0;
  if (frame++ == 64) {
    std::cout << "lx: " << lx << " ly: " << ly << " rx: " << rx << std::endl;
  }

  const float dead = 0.1f;
  if (abs(lx) < dead) lx = 0.0f;
  if (abs(ly) < dead) ly = 0.0f;
  if (abs(rx) < dead) rx = 0.0f;

  float speed = move_speed * (shifted ? 2.0f : 1.0f);
  if(zoom >= 1.0f) {
    speed /= zoom;
  }

  // Move with left stick
  pos.x += lx * speed;
  pos.y += ly * speed;

  // Rotation with right stick x-axis
  rotation += rx * 2.0f;

  shifted = SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER);
}

void Camera::on_mouse_motion(float dx, float dy) {
  // Not used in 2D mode
  (void)dx;
  (void)dy;
}

CameraUBO Camera::ubo(float aspect) const {
  return CameraUBO{
      .cam_pos = vec4(pos.x, pos.y, 5.0f, 1.0f),
      .time = (float)SDL_GetTicks() / 1000.0f,
      .aspect = aspect
  };
}
