#include "exitcleanup.hpp"
#include "init.hpp"
#include "types.hpp"
#include <SDL3/SDL.h>
#include <SDL3_image/SDL_image.h>
#include <cmath>
#include <csignal>
#include <iostream>
#include <vector>
#include <ctime>
#include <iomanip>

std::vector<Entity *> loaded_entities;
sdl_session main_sdl_session;

int main() {
  SDL_Init(SDL_INIT_VIDEO);

  main_sdl_session.window =
      SDL_CreateWindow("Naval Swarm", SCREEN_WIDTH, SCREEN_HEIGHT, 0);
  SDL_Renderer *renderer =
      SDL_CreateRenderer(main_sdl_session.window, "gpu,vulcan");

  // Load textures
  SDL_Texture *bgTexture = IMG_LoadTexture(renderer, "assets/background.png");

  // Initialize player
  Entity destroyer;

  init_entity(destroyer, renderer, "ship", "destroyer");

  destroyer.position = {WORLD_WIDTH / 2.0f, WORLD_HEIGHT / 2.0f,
                        static_cast<float>(destroyer.srcRect.w),
                        static_cast<float>(destroyer.srcRect.h)};

  // Initialize camera
  Camera camera;
  bool running = true;
  Uint64 lastFrameTime = SDL_GetTicksNS();
  float deltaTime = 0.0f;

  time_t start_time = std::time(nullptr);

  while (running) {
    const Uint64 frameStart = SDL_GetTicksNS();


    // Event handling
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
      if (event.type == SDL_EVENT_QUIT) {
        running = false;
      }
      if (event.type == SDL_EVENT_MOUSE_WHEEL) {
        float zoom_factor = (event.wheel.y > 0) ? 0.9f : 1.1f;
        camera.view.w *= zoom_factor;
        camera.view.h *= zoom_factor;

        // Zoom towards mouse position
        SDL_FPoint mouse_world_pos = {
            camera.view.x + event.wheel.mouse_x,
            camera.view.y + event.wheel.mouse_y
        };
        
        camera.view.x = mouse_world_pos.x - (event.wheel.mouse_x * zoom_factor);
        camera.view.y = mouse_world_pos.y - (event.wheel.mouse_y * zoom_factor);
    }
      if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
        // Check specific button (e.g., left mouse button)
        if (event.button.button == SDL_BUTTON_LEFT) {
          std::clog << "Left mouse clicked at (" 
          << std::fixed << std::setprecision(1) << event.button.x << ", " << event.button.y << ")\n"
          << "Camera position: (" << camera.view.x << ", " << camera.view.y << ")\n"
          << "Target position: (" << (camera.view.x + event.button.x) << ", " 
          << (camera.view.y + event.button.y) << ")\ntime since start: " << (std::time(nullptr) - start_time) << "\n";
          destroyer.Tposition.x = camera.view.x + event.button.x;
          destroyer.Tposition.y = camera.view.y + event.button.y;
          destroyer.gotoT = true;
        }
      }
    }

    // Input handling
    const bool *keystate = SDL_GetKeyboardState(NULL);

    // Toggle camera mode with C key
    static Uint32 lastToggle = 0;
    if (keystate[SDL_SCANCODE_C] && (SDL_GetTicks() - lastToggle > 200)) {
      camera.followPlayer = !camera.followPlayer;
      lastToggle = SDL_GetTicks();
    }

    //DEBUG
    if (keystate[SDL_SCANCODE_B] && (SDL_GetTicks() - lastToggle > 200)) {
      std::clog << "x: " << destroyer.position.x << " y: " << destroyer.position.y << "\n";
    }
    if (keystate[SDL_SCANCODE_O] && (SDL_GetTicks() - lastToggle > 200)) {

      destroyer.position.x = 0;
      destroyer.position.y = 0;
        }

    // Player movement
    int moveX = keystate[SDL_SCANCODE_RIGHT] - keystate[SDL_SCANCODE_LEFT];
    int moveY = keystate[SDL_SCANCODE_DOWN] - keystate[SDL_SCANCODE_UP];

    // There is propably more eficient way to do this
    switch (moveX) {
    case 1:
      switch (moveY) {
      case 1:
        destroyer.angle = 135;
        break;
      case -1:
        destroyer.angle = 45;
        break;
      default:
        destroyer.angle = 90;
      }
      break;
    case -1:
      switch (moveY) {
      case 1:
        destroyer.angle = 225;
        break;
      case -1:
        destroyer.angle = 315;
        break;
      default:
        destroyer.angle = 270;
      }
      break;
    default:
      switch (moveY) {
      case 1:
        destroyer.angle = 180;
        break;
      case -1:
        destroyer.angle = 0;
        break;
      }
    }

    float step = destroyer.speed * deltaTime;
    destroyer.position.x += (float)moveX * step;
    destroyer.position.y += (float)moveY * step;

    if (destroyer.gotoT) {
      float dx = destroyer.Tposition.x - destroyer.Central_position().x;
      float dy = destroyer.Tposition.y - destroyer.Central_position().y;

      if(dx != 0 && dy != 0) {
        destroyer.angle = std::atan2(dy, dx) * 180 / M_PI + 90;
      }

      float distance = std::sqrt(dx * dx + dy * dy);
      if (distance > 0) {
        dx /= distance;
        dy /= distance;

        if (distance <= step) {
          destroyer.Central_position(destroyer.Tposition.x,
                                     destroyer.Tposition.y);

        } else {
          destroyer.position.x += dx * step;
          destroyer.position.y += dy * step;
        }

      } else {
        destroyer.gotoT = false;
      }
    }

    // Camera handling
    camera.view.w = SCREEN_WIDTH / camera.zoom;
    camera.view.h = SCREEN_HEIGHT / camera.zoom;

    if (camera.followPlayer) {
      float targetX =
          destroyer.position.x + destroyer.position.w / 2 - camera.view.w / 2;
      float targetY =
          destroyer.position.y + destroyer.position.h / 2 - camera.view.h / 2;
      camera.view.x += (targetX - camera.view.x) * camera.smoothness;
      camera.view.y += (targetY - camera.view.y) * camera.smoothness;
    } else {
      float camMoveX = keystate[SDL_SCANCODE_D] - keystate[SDL_SCANCODE_A];
      float camMoveY = keystate[SDL_SCANCODE_S] - keystate[SDL_SCANCODE_W];
      camera.view.x += camMoveX * camera.speed * deltaTime;
      camera.view.y += camMoveY * camera.speed * deltaTime;
    }

    // World bounds
    destroyer.position.x = SDL_clamp(destroyer.position.x, 0.0f,
                                     WORLD_WIDTH - destroyer.position.w);
    destroyer.position.y = SDL_clamp(destroyer.position.y, 0.0f,
                                     WORLD_HEIGHT - destroyer.position.h);

    camera.view.w = SDL_clamp(camera.view.w, SCREEN_WIDTH * camera.zoom,  SCREEN_WIDTH * 4.0f);
    camera.view.h = SDL_clamp(camera.view.h,SCREEN_HEIGHT * camera.zoom,SCREEN_HEIGHT * 4.0f);
    camera.view.x = SDL_clamp(camera.view.x, 0.0f, WORLD_WIDTH - camera.view.w);
    camera.view.y = SDL_clamp(camera.view.y, 0.0f, WORLD_HEIGHT - camera.view.h);

    // ANIMATION HERE

    // Rendering
    SDL_SetRenderDrawColor(renderer, 30, 30, 45, 255);
    SDL_RenderClear(renderer);

    // Draw background
    if (bgTexture) {
      SDL_FRect bgDest = {-camera.view.x, -camera.view.y, WORLD_WIDTH,
                          WORLD_HEIGHT};
      SDL_RenderTexture(renderer, bgTexture, NULL, &bgDest);
    }

    // Draw player (simplified without animation)
    SDL_FRect srcFRect;
    SDL_RectToFRect(&destroyer.srcRect, &srcFRect);
    SDL_FRect destRect = {destroyer.position.x - camera.view.x,
                          destroyer.position.y - camera.view.y,
                          destroyer.position.w, destroyer.position.h};
    SDL_RenderTextureRotated(renderer, destroyer.texture, &srcFRect, &destRect,
                             destroyer.angle, nullptr, SDL_FLIP_NONE);

    SDL_RenderPresent(renderer);

    // Frame timing (unchanged)
    const Uint64 frameTime = SDL_GetTicksNS() - frameStart;
    if (frameTime < TARGET_FRAME_TIME_NS) {
      const Uint64 sleepTime = TARGET_FRAME_TIME_NS - frameTime;
      SDL_DelayNS(sleepTime - 2'000'000);
      while (SDL_GetTicksNS() - frameStart < TARGET_FRAME_TIME_NS) {
      }
    }

    deltaTime = (SDL_GetTicksNS() - lastFrameTime) / 1e9f;
    lastFrameTime = SDL_GetTicksNS();
  }

  // Cleanup
  SDL_DestroyTexture(bgTexture);
  GeneralCleanUp();
  SDL_Quit();
  return 0;
}
