#!/usr/bin/env lua5.1

local marigold = require 'marigold-cgi.marigold'
local h        = marigold.h
local b64      = require '3rdparty.base64'
local json     = require '3rdparty.json'


-- get statistics
local metavars = marigold.get_metavars()
local query = marigold.decode_query(metavars.query_string or '')
local function query_retrieve(key, default)
	local key = 'stat_'..key
	if query[key] ~= '' then return query[key]
	else return default
	end
end
local stat = {
	name      = query_retrieve('name', 'Name'),
	alignment = query_retrieve('alignment', 'neutral'),
	size      = query_retrieve('size', 'medium'),
	type      = query_retrieve('type', 'creature'),

	ac    = query_retrieve('ac', '0'),
	hp    = query_retrieve('hp', '0'),
	speed = query_retrieve('speed', '0 ft.'),

	str = query_retrieve('str', '10'), 
	dex = query_retrieve('dex', '10'), 
	con = query_retrieve('con', '10'), 
	int = query_retrieve('int', '10'), 
	wis = query_retrieve('wis', '10'), 
	cha = query_retrieve('cha', '10'), 

	saving_throws   = (query.stat_saving_throws ~= '' and query.stat_saving_throws) or '',
	vulnerabilities = (query.stat_vulnerabilities ~= '' and query.stat_vulnerabilities) or '',
	resistances     = (query.stat_reistances ~= '' and query.stat_reistances) or '',
	immunities      = (query.stat_immunities ~= '' and query.stat_immunities) or '',
	condition_immunities = (query.stat_condition_immunities ~= '' and query.stat_condition_immunities) or '',
	languages = (query.stat_languages ~= '' and query.stat_languages) or '',
	cr = (query.stat_cr ~= '' and query.stat_cr) or '',

	traits = query.stat_traits or [[@New Trait
Add a named trait with an at sign. All lines following until the next at sign 
will be part of the trait description!

@Second Trait
This is a different trait.
]],
	actions = query.stat_actions or [[
@New Action
Actions (and reactions and legendary actions) use the same syntax as traits. As well,
in all of them you can add *italics* and **bold** text!
]],
	reactions = query.stat_reactions or '',
	legendary_description = query.stat_legendary_description  or '',
	legendary = query.stat_legendary or '',
}



-- stats yarrow query conversion
local function clean(str)
	local str = string.gsub(str, '^%s+', '')
	local str = string.gsub(str, '%s+$', '')
	return str
end
local function parse_traits(str)
	local tbl = {}
	for name, value in string.gmatch(str, '@([^@]-)\n([^@]+)') do
		table.insert(tbl, {name=clean(name), value=clean(value)})
	end
	if #tbl == 0 then return nil end
	return tbl
end
local function convert(stats)
	local tbl = {}
	for k, v in pairs(stats) do
		if v ~= '' then
			tbl[k] = v
		end
	end
	if tbl.traits ~= '' then
		tbl.traits = parse_traits(stats.traits)
	else tbl.traits = nil end
	if tbl.traits ~= '' then
		tbl.actions = parse_traits(stats.actions)
	else tbl.actions = nil end
	if tbl.reactions ~= '' then
		tbl.reactions = parse_traits(stats.reactions)
	else tbl.reactions = nil end
	if stats.legendary ~= '' then
		tbl.legendary = {}
		tbl.legendary.description = stats.legendary_description
		tbl.legendary.actions = parse_traits(stats.legendary)
	end
	return json.encode(tbl)
end


-- form helpers
local function text_input(label, name, value)
	local tbl = {}
	tbl['for'] = name
	return h('div', { class='inputdiv',
		h('label', label, tbl),
		h('input', { type='text', id=name, name=name, value=value }),
	})
end
local function textarea(label, name, value, height)
	local tbl = {}
	tbl['for'] = name
	return h('div', { class='inputdiv',
		h('label', label, tbl),
		h('textarea', value, { id=name, name=name, style=(height and 'height:'..height) or nil }),
	})
end


-- stats form
local form_basic = h('form', { style="width:100%; max-width: 30em; margin: auto; padding: 3em 0;", 
	text_input('Name', 'stat_name', stat.name),
	text_input('Alignment', 'stat_alignment', stat.alignment),
	text_input('Size', 'stat_size', stat.size),
	text_input('Type', 'stat_type', stat.type),
	h('br'),

	text_input('Armor Class', 'stat_ac', stat.ac),
	text_input('Hit Points', 'stat_hp', stat.hp),
	text_input('Speed', 'stat_speed', stat.speed),
	h('br'),

	text_input('STR', 'stat_str', stat.str),
	text_input('DEX', 'stat_dex', stat.dex),
	text_input('CON', 'stat_con', stat.dex),
	text_input('INT', 'stat_int', stat.int),
	text_input('WIS', 'stat_wis', stat.wis),
	text_input('CHA', 'stat_cha', stat.cha),
	h('br'),

	text_input('Saving Throws', 'stat_saving_throws', stat.saving_throws),
	text_input('Damage Vulnerabilities', 'stat_vulnerabilities', stat.vulnerabilities),
	text_input('Damage Resistances', 'stat_resistances', stat.resistances),
	text_input('Damage Immunities', 'stat_immunities', stat.immunities),
	text_input('Condition Immunities', 'stat_condition_immunities', stat.condition_immunities),
	text_input('Senses', 'stat_senses', stat.senses),
	text_input('Languages', 'stat_languages', stat.languages),
	text_input('Challenge', 'stat_cr', stat.cr),
	h('br'),

	textarea('Additional Traits', 'stat_traits', stat.traits, '20em'),
	h('br'),
	textarea('Actions', 'stat_actions', stat.actions, '20em'),
	h('br'),
	textarea('Reactions', 'stat_reactions', stat.reactions, '20em'),
	h('br'),
	textarea('Legendary Action Text', 'stat_legendary_description', stat.legendary_description, '5em'),
	textarea('Legendary Actions', 'stat_legendary', stat.legendary, '20em'),
	h('br'),
	h('div', { style='text-align:center',
		h('button', 'Update', { type='submit' }),
	})
})


local img = h('div', { style='text-align: center', 
	h('img', { style="max-width:500px", width='90%', src='yarrow.cgi?statistics='..b64.encode(convert(stat)) }),
	h('br'),
	h('a', 'image permalink', { id="permalink", href='yarrow.cgi?statistics='..b64.encode(convert(stat)) }),
})


local head = h('head', {
	h('meta', { charset='utf-8' }),
	h('meta', { name='viewport', content='width=device-width, initial-scale=1' }),
	h('title', 'yarrow config'),
	h('link', { rel='stylesheet', href='style.css' }),
	h('script', string.format([[
		window.onload = () => {
			const link = document.getElementById('permalink');
			const br = document.createElement('br');

			const button = document.createElement('button');
			button.textContent = 'copy link';
			button.addEventListener('click', () => {
				navigator.clipboard.writeText('%s');
				button.textContent = 'copied!';
				setTimeout(() => button.textContent = 'copy link', 1000);
			});

			link.after(br, button);
		};
	]], 'https://sanine.net/utils/yarrow/yarrow.cgi?statistics='..b64.encode(convert(stat))), { type='text/javascript' }),
})


local body = h('body', {
	form_basic,
	img,
	h('hr'),
	h('a', 'source code', { href='https://sanine.net/git/yarrow' }),
})


print('Content-type: text/html\n')
print(marigold.html(h('html', { head, body })))