import { cls, get_dimensions, scale } from "./graphics";
import { since_start } from "./time";
import { new_v2 } from "./vector";
import { load_world, World, draw_level } from "./level";
import {
  Actor,
  ActorProps,
  ActorType,
  new_actor_props,
  is_actor_type,
  spawn_actor,
} from "./actor";
import { log, draw_log } from "./log";

/// A nice looping frame counter.
let clock = 0;

let world: World | undefined = undefined;
let actors: Actor[] = [];

// Note zelda overworld is 16x8 screens
//      zelda screen is 16x11 tiles
// from a feeling point of view this is sufficient, apparently :D

function start_load_assets() {
  // Start this load, but then...
  load_world("./overworld.ldtk").then((w) => {
    log("world loaded at", since_start());
    world = w;

    // Assume we start at 0,0
    const level = world.current_level;

    // TODO: SPAWN ACTORS BASED ON LEVEL.
    actors.length = 0;
    for (const entity of level.entities) {
      if (is_actor_type(entity.type)) {
        const [x, y] = entity.px;
        const [w, _] = entity.bounds;
        const props = new_actor_props(entity.id, new_v2(x, y), w);
        actors.push(spawn_actor(entity.type, props));
      } else {
        log("WARNING: Ignoring entity of type", entity.type);
      }
    }
  });
}

// TODO: Build a system whereby the signatures of the fundamental functions can be checked.

export function init() {
  log("Hello world!");
  start_load_assets();
}

interface Snapshot {
  clock: number;
  actors: { type: ActorType; props: ActorProps }[];
}

export function suspend(): Snapshot {
  log("suspend_status", "Suspend ", actors.length, "actors");
  return {
    clock,
    actors: actors.map((a) => {
      return { type: a.type, props: a.props };
    }),
  };
}

export function resume(snapshot: Snapshot | undefined) {
  if (snapshot) {
    clock = snapshot.clock || 0;
    actors = snapshot.actors.map((s) => spawn_actor(s.type, s.props));
    log("resume_status", "Resume ", actors.length, "actors");
  }
}

export function update() {
  if (!world) {
    return;
  }

  clock = (clock + 1) % 20160;

  for (const actor of actors) {
    actor.update(world);
  }

  // TODO: Bonks
  // TODO: Transients
}

export function draw() {
  cls(0.1, 0.2, 0.3);

  const dimensions = get_dimensions();
  const s = Math.max(
    1,
    Math.floor(Math.min(dimensions[0] / 320, dimensions[1] / 240))
  );
  scale(s);

  if (world != undefined) {
    draw_level(world.current_level, 0, 0);
  }

  for (const actor of actors) {
    actor.draw(clock);
  }

  // log("FRAME TIME:", since_last_frame());
  draw_log();
}
