local gui = require("gui")
local events = import("events", "local")

local cameras = {}

local function make_camera(x, y, w, h)
    if not gui.camera then
        gui.mouse.mode = 1
    end
    local camera = {
        base = gui.make_camera(w, h)
    }
    camera.base.type = "perspective"
    camera.base.fov = 60
    camera.base.height = 3
    camera.base.speed = 5
    camera.rotationY = 0
    camera.rotationX = 0
    camera.active = true
    if x then
        camera.base.x = x
    else
        camera.base.x = 0
    end
    if y then
        camera.base.y = y
    else
        camera.base.y = 0
    end

    function camera.update(v)
        if v then
            camera.base.position = v
        else
            v = camera.base.position
        end
        local x = v.x + math.cos(camera.rotationX) * math.cos(camera.rotationY)
        local y = v.y + math.sin(camera.rotationX)
        local z = v.z + math.cos(camera.rotationX) * math.sin(camera.rotationY)
        camera.base.target = {x, y, z}
    end

    function camera.move(v)
        local p = camera.base.position
        if v.forward then
            local x = v.forward * math.cos(camera.rotationY)
            local z = v.forward * math.sin(camera.rotationY)
            p = { x = p.x + x, y = p.y, z = p.z + z }
        end
        if v.right then
            local x = v.right * math.cos(camera.rotationY + math.pi/2)
            local z = v.right * math.sin(camera.rotationY + math.pi/2)
            p = { x = p.x + x, y = p.y, z = p.z + z }
        end
        return p
    end

    function camera.apply()
        camera.base:apply()
    end

    cameras[#cameras + 1] = camera
    camera.update()

    return setmetatable(camera, {
        __index = function(t, k)
            return t.base[k]
        end,
        __newindex = function(t, k, v)
            t.base[k] = v
        end
    })
end

local main = make_camera()

events.update += function(dt)
    for _, camera in pairs(cameras) do
        if not camera.active then
            return
        end
        if gui.keyboard.held.W then
            camera.update(camera.move({ forward = dt*camera.base.speed }))
        end
        if gui.keyboard.held.S then
            camera.update(camera.move({ forward = -dt*camera.base.speed }))
        end
        if gui.keyboard.held.A then
            camera.update(camera.move({ right = -dt*camera.base.speed }))
        end
        if gui.keyboard.held.D then
            camera.update(camera.move({ right = dt*camera.base.speed }))
        end
        if gui.mouse.ScrollWheel ~= 0 then
            camera.base.fov = camera.base.fov - gui.mouse.ScrollWheel / 120
            printf("fov: %f", camera.base.fov)
            gui.mouse:ResetScrollWheelValue()
            camera.update()
        end
        if gui.mouse.mode == 1 then
            camera.rotationY = camera.rotationY + gui.mouse.x / 1000 * math.pi / 2
            camera.rotationX = math.max(math.min(camera.rotationX - gui.mouse.y / 1000 * math.pi / 2, math.pi*.4995), -math.pi*.4995)
        end
        camera.update()
    end
end

return setmetatable({
    main = main,
    new = make_camera
}, {
    __index = main,
    __newindex = main
})