/*
 * Copyright 2024 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef UI_DEBUG
#include "ui_nudge.h"

#include "console_internal.h"
#include "dbgserial.h"

#include "applib/ui/layer.h"
#include "applib/ui/ui_debug.h"
#include "applib/ui/app_window_stack.h"
#include "applib/ui/window_stack_private.h"

#include "kernel/events.h"

#include "services/common/compositor/compositor.h"
#include "util/string.h"

static Layer *s_nudge_layer = NULL;

static void prv_flush_kernel_main_cb(void *unused) {
  // FIXME compositor_flush();
}

void layer_debug_nudging_handle_character(char c, bool *should_context_switch) {
  GRect frame = s_nudge_layer->frame;
  GRect bounds = s_nudge_layer->bounds;
  switch (c) {
    case 0x3: // CTRL - C
      s_nudge_layer = NULL;
      // Back to log mode:
      serial_console_set_state(SERIAL_CONSOLE_STATE_LOGGING);
      // Dump window:
      command_dump_window();
      return;

    case 'A':
    case 'a':
      --frame.origin.x;
      break;

    case 'D':
    case 'd':
      ++frame.origin.x;
      break;

    case 'W':
    case 'w':
      ++frame.origin.y;
      break;

    case 'S':
    case 's':
      --frame.origin.y;
      break;

    case '[':
      --frame.size.w;
      bounds.size = frame.size;
      break;

    case ']':
      ++frame.size.w;
      bounds.size = frame.size;
      break;

    case '{':
      --frame.size.h;
      bounds.size = frame.size;
      break;

    case '}':
      ++frame.size.h;
      bounds.size = frame.size;
      break;

    default:
      break;
  }
  layer_set_frame(s_nudge_layer, &frame);
  layer_set_bounds(s_nudge_layer, &bounds);

  PebbleEvent event = {
    .type = PEBBLE_CALLBACK_EVENT,
    .callback = {
      .callback = prv_flush_kernel_main_cb,
      .data = NULL,
    },
  };
  *should_context_switch = event_put_isr(&event);
}

void command_layer_nudge(const char *address_str) {
  intptr_t address = str_to_address(address_str);
  if (address == -1) {
    return;
  }
  // Simple sanity check:
  if (((Layer *)address)->window != app_window_stack_get_top_window()) {
    dbgserial_putstr("Specify valid Layer address!");
    return;
  }
  s_nudge_layer = (Layer *)address;

  dbgserial_putstr("Layer nudging mode, CTRL-C to stop");
  dbgserial_putstr("Keys:\nWASD: Move frame.origin\n[]: Change frame.size.w & bounds.size.w\n{}: Change frame.size.h & bounds.size.h");
  serial_console_set_state(SERIAL_CONSOLE_STATE_LAYER_NUDGING);
}
#endif /* UI_DEBUG */
