#include "event_system.h"
#include <stdio.h>

typedef struct window_event WindowEvent;
typedef struct keyboard_event KeyboardEvent;
typedef struct mouse_event MouseEvent;

struct window_event {
  int window_width;
  int window_height;
};

struct keyboard_event {
  int key;
};

struct mouse_event {
  int x;
  int y;
};

enum event_ids {
  EVENT_WINDOW,
  EVENT_KEYBOARD,
  EVENT_MOUSE,

  COUNT_EVENTS,
};

void window_event_handler(void *data);
void keyboard_event_handler(void *data);
void mouse_event_handler(void *data);
void extra_event_handler(void *data);

int main(void) {
  Event         events   [COUNT_EVENTS] = {0};
  EventListener listeners[COUNT_EVENTS] = {0};
  EventCallback callbacks[COUNT_EVENTS] = {window_event_handler, keyboard_event_handler, mouse_event_handler};

  EventSystem es = es_init(COUNT_EVENTS, 64);

  for (int i = 0; i < COUNT_EVENTS; ++i) {
    events[i]    = es_register_event(&es);
    listeners[i] = es_add_event_listener(es, events[i], callbacks[i]);
  }

  WindowEvent   window_event   = { .window_width = 1280, .window_height = 720 };
  KeyboardEvent keyboard_event = { .key = 120 };
  MouseEvent    mouse_event    = { .x = 628, .y = 154 };

  printf("FROM MAIN\n");
  printf("    WIDTH: %d, HEIGHT: %d\n", window_event.window_width, window_event.window_height);
  es_emit_event(es, events[EVENT_WINDOW],   (void *)&window_event);

  printf("FROM MAIN\n");
  printf("    KEY: %d\n", keyboard_event.key);
  es_emit_event(es, events[EVENT_KEYBOARD], (void *)&keyboard_event);

  printf("FROM MAIN\n");
  printf("    X: %d, Y: %d\n", mouse_event.x, mouse_event.y);
  es_emit_event(es, events[EVENT_MOUSE],    (void *)&mouse_event);

  // You can also add other events not stored in an array
  Event         extra_event = es_register_event(&es);
  EventListener listener    = es_add_event_listener(es, extra_event, extra_event_handler);
  es_emit_event(es, extra_event, NULL);
  es_remove_event_listener(es, listener);
  es_deregister_event(&es, &extra_event);

  for (int i = 0; i < COUNT_EVENTS; ++i) {
    es_remove_event_listener(es, listeners[i]);
    es_deregister_event(&es, &events[i]);
  }

  es_deinit(&es);

  return 0;
}

void window_event_handler(void *data) {
  if (!data) {
    return;
  }

  WindowEvent *ev = (WindowEvent *)data;

  printf("FROM CALLBACK\n");
  printf("    WIDTH: %d, HEIGHT: %d\n\n", ev->window_width, ev->window_height);
}

void keyboard_event_handler(void *data) {
  if (!data) {
    return;
  }

  KeyboardEvent *ev = (KeyboardEvent *)data;

  printf("FROM CALLBACK\n");
  printf("    KEY: %d\n\n", ev->key);
}

void mouse_event_handler(void *data) {
  if (!data) {
    return;
  }

  MouseEvent *ev = (MouseEvent *)data;

  printf("FROM CALLBACK\n");
  printf("    X: %d, Y: %d\n\n", ev->x, ev->y);
}

void extra_event_handler(void *data) {
  printf("Calling extra_event_handler\n\n");
}