#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/cursorfont.h>
#include <X11/Xft/Xft.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include <unistd.h>

#include "src/common.h"
#include "src/time.h"
#if defined(__OpenBSD__)
#include "src/battery.h"
#include "src/volume.h"
#endif

#define BAR_HEIGHT 36
#define FONT "Noto Sans CJK JP-10"
#define BLACK 0x120f12

const char *sofname = "unixbar";
const char *version = "0.1.0";

int get_current_workspace(Display *dp, Window root) {
  Atom actual_type;
  int actual_format;
  unsigned long nitems, bytes_after;
  unsigned char *prop = NULL;
  Atom _NET_CURRENT_DESKTOP = XInternAtom(dp, "_NET_CURRENT_DESKTOP", False);
  int workspace = 0;

  if (XGetWindowProperty(
    dp,
    root,
    _NET_CURRENT_DESKTOP,
    0,
    1,
    False,
    XA_CARDINAL, 
    &actual_type,
    &actual_format,
    &nitems,
    &bytes_after,
    &prop
  ) == Success) {
    if (prop != NULL) {
      workspace = (int) *prop;
      XFree(prop);
    }
  }
  
  return workspace;
}

Window *get_open_windows(Display *dp, Window root, unsigned long *nwindows) {
  Atom _NET_CLIENT_LIST = XInternAtom(dp, "_NET_CLIENT_LIST", False);
  Atom _NET_WM_DESKTOP = XInternAtom(dp, "_NET_WM_DESKTOP", False);
  
  Atom actual_type;
  int actual_format;
  unsigned long nitems, bytes_after;
  unsigned char *prop = NULL;

  if (XGetWindowProperty(
    dp,
    root,
    _NET_CLIENT_LIST,
    0,
    ~0L,
    False,
    XA_WINDOW,
    &actual_type,
    &actual_format,
    &nitems,
    &bytes_after,
    &prop
  ) != Success) {
    return NULL;
  }

  Window *windows = (Window *)prop;
  *nwindows = nitems;
  unsigned long current_workspace =
    (unsigned long)get_current_workspace(dp, root);

  unsigned long j = 0;
  for (unsigned long i = 0; i < nitems; i++) {
    unsigned long desktop;
    Atom type;
    int format;
    unsigned long nitems2, bytes_after2;
    unsigned char *prop2 = NULL;
    
    if (XGetWindowProperty(
      dp,
      windows[i],
      _NET_WM_DESKTOP,
      0,
      1,
      False,
      XA_CARDINAL, 
      &type,
      &format,
      &nitems2,
      &bytes_after2,
      &prop2
    ) == Success) {
      if (prop2 != NULL) {
        desktop = *(unsigned long *)prop2;
        XFree(prop2);

        if (desktop == current_workspace) {
          windows[j++] = windows[i];
        }
      }
    }
  }

  *nwindows = j;
  return windows;
}

int main() {
  Display *dp;
  int screen;
  Window root, win;
  XEvent ev;
  GC gc;
  XGCValues values;
  int width, height;
  Window *windows;
  unsigned long nwindows;
  bool istime = true;

  dp = XOpenDisplay(NULL);
  if (dp == NULL) {
    fprintf(stderr, "画面を開けられません\n");
    return 1;
  }

  screen = DefaultScreen(dp);
  root = RootWindow(dp, screen);

  width = DisplayWidth(dp, screen);
  height = BAR_HEIGHT;

  win = XCreateSimpleWindow(
    dp,
    root,
    0,
    0,
    width,
    height,
    0,
    BLACK,
    BLACK
  );

  XSetWindowAttributes attrs;
  attrs.override_redirect = True;
  XChangeWindowAttributes(dp, win, CWOverrideRedirect, &attrs);

  XSelectInput(dp, win, ExposureMask | StructureNotifyMask);
  XMapWindow(dp, win);

  int depth = DefaultDepth(dp, screen);
  Pixmap buf = XCreatePixmap(dp, win, width, height, depth);
  XftDraw *xft_draw = XftDrawCreate(
    dp, buf, DefaultVisual(dp, screen), DefaultColormap(dp, screen)
  );
  XftFont *xft_font = XftFontOpenName(dp, screen, FONT);
  XftColor xft_color;
  XRenderColor render_color = {0xffEA, 0x0079, 0xffD8, 0xffff};
  XftColorAllocValue(
    dp, DefaultVisual(dp, screen), DefaultColormap(dp, screen),
    &render_color, &xft_color
  );

  gc = XCreateGC(dp, win, 0, &values);

  while (1) {
    while (XPending(dp)) {
      XNextEvent(dp, &ev);
      if (ev.type == Expose) {
        break;
      } else if (ev.type == ButtonPress) {
        XButtonEvent *bev = (XButtonEvent *)&ev;
        printf("fuck you\n");

        if (bev->x > width - 80 && bev->x < width) {
          istime = !istime;
          printf("timedate\n");
        } else if (nwindows > 0) {
          unsigned long window_index = bev->x / (width / nwindows);
          if (window_index < nwindows) {
            XRaiseWindow(dp, windows[window_index]);
          }
        }
      }
    }

    int workspace = get_current_workspace(dp, root);

    windows = get_open_windows(dp, root, &nwindows);
    if (windows == NULL) {
      fprintf(stderr, "ウィンドウを開くに失敗\n");
      continue;
    }

    XSetForeground(dp, gc, BLACK);
    XFillRectangle(dp, buf, gc, 0, 0, width, height);

    XftDrawChange(xft_draw, buf);

    char workspace_str[10];
    snprintf(workspace_str, 10, "W%d", workspace);
    draw_text(xft_draw, &xft_color, xft_font, 10, height - 10, workspace_str);

    int xpos = 50;
    if (nwindows > 0) {
      int window_width = 200;
      for (unsigned long i = 0; i < nwindows; i++) {
        char *name;
        XFetchName(dp, windows[i], &name);
        if (!name) name = "不明";
        if (nwindows < 7) {
          draw_text(xft_draw, &xft_color, xft_font, xpos, height - 10, name);
          xpos += window_width;
        } else {
          draw_text(xft_draw, &xft_color, xft_font, xpos, height - 10, "複数");
          xpos = 50;
        }
      }
    }

    int batw = width - 80;
    if (istime) {
      char *time_str = get_current_time();
      if (time_str)
        draw_text(xft_draw, &xft_color, xft_font, batw, height - 10, time_str);
    } else {
      char *date_str = get_current_date();
      if (date_str)
        draw_text(xft_draw, &xft_color, xft_font, batw, height - 10, date_str);
    }
#if defined(__OpenBSD__)
    bool batfull = false;
    struct batinfo bstat;
    char *batperc = get_battery_percent(&bstat);
    if (batperc) {
      int batw = width - 190;
      if (strncmp(batperc, "BAT: 100% |", 11) == 0) batfull = true;
      if (!batfull) batw = width - 180;
      draw_text(xft_draw, &xft_color, xft_font, batw, height - 10, batperc);
      free(batperc);
    }

    bool volfull = false;
    char *volperc = get_volume();
    if (volperc) {
      int volw = width - 280;
      if (strncmp(volperc, "VOL: 100% |", 11) == 0) volfull = true;
      if (volfull && batfull) volw = width - 300;
      else if (volfull || batfull) volw = width - 290;
      draw_text(xft_draw, &xft_color, xft_font, volw, height - 10, volperc);
      free(volperc);
    }
#endif

    XCopyArea(dp, buf, win, DefaultGC(dp, screen), 0, 0, width, height, 0, 0);
    XFlush(dp);
    sleep(1);
  }

  XftDrawDestroy(xft_draw);
  XftFontClose(dp, xft_font);
  XftColorFree(
    dp, DefaultVisual(dp, screen),
    DefaultColormap(dp, screen), &xft_color
  );
  XFreePixmap(dp, buf);
  XCloseDisplay(dp);

  return 0;
}