import "luxe: render" for Render, RenderLayerDesc, PassLayerDesc, LoadAction
import "luxe: render" for SortType, ImageDesc, ImageType, PixelFormat, Image
import "luxe: math" for Math
import "luxe: io" for IO
import "luxe: events" for Events

import "math/math" for M
import "math/util" for Util
import "math/vector" for Vector
import "math/rect" for AABB
import "globals" for Globals
import "blocks/debug" for Holder

class Renderer {

  target{ "scene" }
  static on_change{ "change" }

  static pixel_width{128}
  pixel_width{Renderer.pixel_width}

  res{_gameRes}
  width{_gameRes.x}
  height{_gameRes.y}

  pixel_size{_pixel_size}

  events{_events}

  construct new() {
    Globals["Renderer"] = this

    _events = Events.new()
    
    _desc = ImageDesc.new()
    _desc.type = ImageType.image2D
    _desc.pixel_format = PixelFormat.rgba8Unorm
    _desc.width = pixel_width
    _desc.height = pixel_width
    
    _rt = Image.create(_desc)
    Render.define_resource(target, _rt)

    System.print("game / render / init / ok")
  } //new

  update_targets(){
    var window = Vector.new(Render.window_w(), Render.window_h())
    _pixel_size = (window.x / pixel_width).floor
    _gameRes = window / _pixel_size
    _gameRes = _gameRes - _gameRes % 2

    System.print("game is now %(res.x) x %(res.y)")

    Globals["GameRect"] = AABB.new((_gameRes.x - pixel_width) / 2, _gameRes.y - pixel_width, pixel_width, pixel_width)
    Globals["UiRect"] = AABB.new(0, 0, _gameRes.x, _gameRes.y - pixel_width)


    var relGameRect = AABB.new(Globals["GameRect"].pos.y0() / _gameRes, Vector.new(pixel_width) / _gameRes)
    Globals["RelativeGameRect"] = relGameRect

    _desc.width = res.x
    _desc.height = res.y
    
    Image.redefine(_rt, _desc)

    _texRect = AABB.new((window - _gameRes*_pixel_size)/2, _gameRes * _pixel_size)

    events.emit(Renderer.on_change)
  }

  game_mouse(mouse_pos){
    var pixel_game_rect = Globals["GameRect"]
    var window = AABB.new(0, 0, Render.window_w(), Render.window_h())
    //what a mess :/
    var screen = AABB.new(_texRect.min_x + pixel_game_rect.min_x * _pixel_size, 
        Render.window_h() - (_texRect.min_y + pixel_game_rect.max_y * _pixel_size), 
        pixel_game_rect.width * _pixel_size, pixel_game_rect.height * _pixel_size)

    return  M.remap(screen.min, screen.max, window.min, window.max, mouse_pos)
  }

  ui_mouse(mouse_pos){
    //good chance this works by luck and is not exact
    var window = AABB.new(0, 0, Render.window_w(), Render.window_h())
    var screen = AABB.new(_texRect.min_x, Render.window_h() - _texRect.max_y, _texRect.width, _texRect.height) //Y- mouse positions are the bane of my existance
    return M.remap(screen.min, screen.max, window.min, window.max, mouse_pos)
  }

  ready() {
    update_targets()
    IO.on("engine.runtime.window.size_changed") {|type, data| 
      update_targets()
    }
  }

  tick(delta) {

  }

  render_path(ctx) {

    if(ctx.path == "game") {
      game_render_path(ctx)
    } else if(ctx.path == "ui") {
      ui_render_path(ctx)
    } else if(ctx.path == "copy_to_screen") {
      target_to_screen(ctx)
    } else if(ctx.path == "clear"){
      clear(ctx)
    }

  } //render_path

  game_render_path(ctx) {

    var layer = RenderLayerDesc.new()
    layer.dest.color[0].render_target = target
    layer.dest.color[0].clear_color = ctx.get("clear_color", [1,1,1,1])
    layer.dest.color[0].load_action = LoadAction.clear
    layer.dest.depth.load_action = LoadAction.clear

    ctx.layer_render("default", layer)

  } //game_render_path

  ui_render_path(ctx) {

    var layer = RenderLayerDesc.new()
    layer.dest.color[0].render_target = target
    layer.dest.color[0].load_action = LoadAction.dont_care
    layer.dest.depth.load_action = LoadAction.clear

    ctx.layer_render("default", layer)

  } //ui_render_path

  target_to_screen(ctx){
    var out_pass = PassLayerDesc.new()
    out_pass.library = "shaders/upscale"
    out_pass.function = "upscale_top_center"
    out_pass.targets = ["screen"]
    out_pass.inputs = {
      "pass.flipy" : true,
      "pass.rect" : _texRect.pos_size_list,
      "pass.image" : {
        "image": target,           //image resource name
        "sampler": "nearest_clamp"  //sampler state
      },
    }

    ctx.layer_pass(out_pass)
  }

  clear(ctx){
    var layer = RenderLayerDesc.new()
    layer.dest.color[0].render_target = target
    layer.dest.color[0].clear_color = [0,0,0,1]
    layer.dest.color[0].load_action = LoadAction.clear
    layer.dest.depth.load_action = LoadAction.clear

    ctx.layer_render("default", layer)
  }

} //Renderer
