-- get raja state
local game = require("main_state")
local timer_util = require("timer_util")

local judgeY = 992
local judgeX = 30
local judgeOffset = 40
local judgeFontHeight = 36

local grooveX = 660
local grooveY = 650

local speechBubbleX = 1600
local speechBubbleY = 374
local speechBubbleFontHeight = 30

local jacketWindowY = 200
local jacketWindowX = 1000


function Append(list, t)
    if t then
        for i, v in pairs(t) do
            table.insert(list, v)
        end
    end
end

local function getDiff(op)
    local diff = tonumber(game.number(op))
    if diff < 0 then
        return diff
    end
    return "+" .. diff
end

-- thanks mr mary
local function getClearType()
    local cleartype = {
        [0] = "PASSED",
        [1] = "FAILED",
        [2] = "A-CLEAR",
        [3] = "LA-CLEAR",
        [4] = "EASY CLEAR",
        [5] = "CLEAR",
        [6] = "HARD CLEAR",
        [7] = "EXH CLEAR",
        [8] = "FC",
        [9] = "PERFECT",
        [10] = "MAX"
    }
    -- clear id
    return cleartype[game.number(370)]
end

local function isBestClear()
    -- target clear < current clear
    if game.number(371) < game.number(370) then
        return "(BEST)"
    else
        return ""
    end
end

-- thanks mr mary
local function getRank()
    local rank = {
        [1] = "AAA",
        [2] = "AA",
        [3] = "A",
        [4] = "B",
        [5] = "C",
        [6] = "D",
        [7] = "E",
        [8] = "F"
    }
    local gradeOptionIdx = 0
    repeat
        gradeOptionIdx = gradeOptionIdx + 1
    until game.option(299 + gradeOptionIdx)
    return rank[gradeOptionIdx]
end

local function isBestRank()
    local nowRank = 0
    local bestRank = 0
    repeat
        nowRank = nowRank + 1
    until game.option(299 + nowRank)
    repeat
        bestRank = bestRank + 1
    until game.option(319 + bestRank)

    -- counter-intuitive, but AAA is 0, and F is 8
    -- so whichever stops earlier is win
    if bestRank > nowRank then
        return "(BEST)"
    else
        return ""
    end
end

local function getIrRank()
    return game.number(179)
end

local function getIrTotal()
    return game.number(180)
end

local function constructIrRankDisplay()
    return game.text(1020) .. ": " .. getIrRank() .. " / " .. getIrTotal()
end

local header = {
    -- type = result
    type = 7,
    name = "win95 result",
    -- skin size
    w = 1920,
    h = 1080,
    -- scene timer
    scene = 3600000,
    -- time until inputs are active
    input = 500,
    -- time it takes to fade out
    fadeout = 100,

    -- me :D
    author = "boons",

    -- config options
    filepath = {
        { name = "CLEAR",  path = "customize/bg/clear/*.png", def = "_Default.png", category = "CLEAR" },
        { name = "FAIL",   path = "customize/bg/fail/*.png",  def = "BSOD.png",     category = "FAIL" },
        { name = "CLIPPY", path = "customize/clippy/*.png",   def = "Clippy.png",   category = "CLIPPY" }
    },
    category = {
        {
            name = "RESULT BG",
            item =
            {
                "CLEAR",
                "FAIL"
            }
        },
        {
            name = "CLIPPY",
            item =
            {
                "CLIPPY"
            }
        }
    }
}

local function main()
    local skin = {}

    -- add header properties into skin
    for k, v in pairs(header) do
        skin[k] = v
    end

    -- tell raja where to look for assets
    skin.source = {
        { id = 0, path = "customize/bg/fail/*.png" },
        { id = 1, path = "customize/bg/clear/*.png" },
        { id = 2, path = "asset/song-data.png" },
        { id = 3, path = "asset/groove-gauge.png" },
        { id = 4, path = "asset/clippy-bubble.png" },
        { id = 5, path = "customize/clippy/*.png" },
        { id = 6, path = "asset/jacket.png" },
        { id = 7, path = "asset/taskbar.png" },
        { id = 8, path = "asset/time-container.png" }
        -- todo: taskbar items
    }

    skin.font = {
        { id = 0, path = "font/SarasaMonoCL-Regular.ttf" }, -- CJK monospace
        { id = 1, path = "font/Windows_Regular.ttf" }       -- clippy speech
    }

    skin.image = {
        { id = "bg_clear",            src = 1, x = 0, y = 0, w = -1, h = -1 },
        { id = "bg_failed",           src = 0, x = 0, y = 0, w = -1, h = -1 },
        { id = "bg_song",             src = 2, x = 0, y = 0, w = -1, h = -1 },
        { id = "bg_groove",           src = 3, x = 0, y = 0, w = -1, h = -1 },
        { id = "clippy_speechbubble", src = 4, x = 0, y = 0, w = -1, h = -1 },
        { id = "clippy_character",    src = 5, x = 0, y = 0, w = -1, h = -1 },
        { id = "jacket_window",       src = 6, x = 0, y = 0, w = -1, h = -1 },
        { id = "taskbar",             src = 7, x = 0, y = 0, w = -1, h = -1 },
        { id = "taskbar_time",        src = 8, x = 0, y = 0, w = -1, h = -1 }
    }

    skin.text = {
        { id = "text_groove_title",      font = 0, size = 40,                     align = 0, overflow = 1, constantText = "GAUGE: " .. game.number(107) .. "." .. game.number(407) .. "%" }, -- gauge
        { id = "text_title",             font = 0, size = 40,                     align = 0, overflow = 2, ref = 12 },                                                                       -- shrink
        { id = "text_level",             font = 0, size = 40,                     align = 0, overflow = 1, ref = 1002 },
        { id = "pgreat",                 font = 0, size = judgeFontHeight,        align = 0, overflow = 1, constantText = "PERFECT: " .. game.number(110) },
        { id = "great",                  font = 0, size = judgeFontHeight,        align = 0, overflow = 1, constantText = "GREAT  : " .. game.number(111) },
        { id = "good",                   font = 0, size = judgeFontHeight,        align = 0, overflow = 1, constantText = "GOOD   : " .. game.number(112) },
        { id = "bad",                    font = 0, size = judgeFontHeight,        align = 0, overflow = 1, constantText = "BAD    : " .. game.number(113) },
        { id = "poor",                   font = 0, size = judgeFontHeight,        align = 0, overflow = 1, constantText = "POOR   : " .. game.number(114) },
        { id = "expoor",                 font = 0, size = judgeFontHeight,        align = 0, overflow = 1, constantText = "EXPOOR : " .. game.number(420) },
        { id = "exscore",                font = 0, size = judgeFontHeight,        align = 0, overflow = 1, constantText = "SCORE  : " .. game.number(171) },
        { id = "exscore_diff",           font = 0, size = judgeFontHeight,        align = 0, overflow = 1, constantText = "BEST   : " .. getDiff(172) },
        { id = "exscore_diff_target",    font = 0, size = judgeFontHeight,        align = 0, overflow = 1, constantText = "TARGET : " .. getDiff(153) },
        -- judge rank
        { id = "total_fast",             font = 0, size = judgeFontHeight,        align = 0, overflow = 1, constantText = "FAST   : " .. game.number(423) },
        { id = "total_slow",             font = 0, size = judgeFontHeight,        align = 0, overflow = 1, constantText = "SLOW   : " .. game.number(424) },
        -- clippy
        { id = "clippy_rank",            font = 1, size = 60,                     align = 0, overflow = 1, constantText = getRank() },
        { id = "clippy_rank_best",       font = 1, size = speechBubbleFontHeight, align = 0, overflow = 1, constantText = isBestRank() },
        { id = "clippy_clear_type",      font = 1, size = speechBubbleFontHeight, align = 0, overflow = 1, constantText = getClearType() },
        { id = "clippy_clear_type_best", font = 1, size = speechBubbleFontHeight, align = 0, overflow = 1, constantText = isBestClear() },
        { id = "clippy_rate",            font = 1, size = speechBubbleFontHeight, align = 0, overflow = 1, constantText = "RATE: " .. game.number(155) .. "." .. game.number(156) .. "%" },
        -- ir
        {
            id = "clippy_ir_rank",
            font = 1,
            size = speechBubbleFontHeight,
            align = 0,
            overflow = 1,
            value = constructIrRankDisplay
        },
        { id = "clippy_ir_unavailable", font = 1, size = speechBubbleFontHeight, align = 0, overflow = 1, constantText = "IR OFFLINE (^^);" },
        --jacket
        { id = "text_jacket_title",     font = 0, size = 40,                     align = 0, overflow = 1, constantText = "JACKET" },
        { id = "jacket_no_jacket",      font = 0, size = 52,                     align = 1, overflow = 1, constantText = "NO JACKET (^^);" },
        -- task bar
        { id = "taskbar_time_text",     font = 1, size = 40,                     align = 0, overflow = 1, constantText = os.date("%c") }
    }

    -- gauge graph
    skin.gaugegraph = {
        { id = "gauge_line", assistClearLineColor = "FF00FF00", assistAndEasyFailLineColor = "00ff0000", grooveFailLineColor = "00ffff00", grooveClearAndHardLineColor = "ff000000", exHardLineColor = "ffff0000", hazardLineColor = "cccccc00", borderlineColor = "ff000000" },
        { id = "gauge_bg",   assistClearBGColor = "ff00ff00",   assistAndEasyFailBGColor = "00ff0000",   grooveFailBGColor = "00ffff00",   grooveClearAndHardBGColor = "ff000000",   exHardBGColor = "ffff0000",   hazardBGColor = "44444400",   borderColor = "eeeeee00" },
    }

    -- put it all to use
    skin.destination = {
        {
            id = "bg_clear",
            op = { 90 }, -- cleared
            dst = {
                { x = 0, y = 0, w = 1920, h = 1080, a = 255, filter = 1 }
            }
        },
        {
            id = "bg_failed",
            op = { 91 }, -- failed
            dst = {
                { x = 0, y = 0, w = 1920, h = 1080, a = 255, filter = 1 }
            }
        }
    }

    local songdata = require("dst.songdata")
    local clippy = require("dst.clippy")
    local gauge = require("dst.gauge")
    local jacket = require("dst.jacket")
    local taskbar = require("dst.taskbar")

    Append(skin.destination, songdata.getSongData(judgeX, judgeY, judgeFontHeight, judgeOffset))
    Append(skin.destination, clippy.getClippy(speechBubbleX, speechBubbleY, speechBubbleFontHeight))
    Append(skin.destination, gauge.getGauge(grooveX, grooveY))
    Append(skin.destination, jacket.getJacket(jacketWindowX, jacketWindowY))
    Append(skin.destination, taskbar.getTaskbar())

    return skin
end

return {
    header = header,
    main = main
}
