const fs = require("fs")
const { parse } = require("csv-parse/sync")

var card_records = parse(fs.readFileSync("tools/cards.csv", "utf-8"), { columns: true, records_with_empty_values: true })
var scenario_records = parse(fs.readFileSync("tools/scenarios.csv", "utf-8"), { columns: true, skip_records_with_empty_values: true })

var result = []

const WING = { red: 0, pink: 1, blue: 2, dkblue: 3 }
const WING_ICON = [ "\u2666", "\u2665", "\u2663", "\u2660" ]

const SQUEEZE_BOXES = [ "82A", "128A", "136B" , "274B", "291A" ]
const SQUEEZE_MARGINS = [ "91B", "239B", "274B", "291A", "69B" ]

var cards = [ ]
var card_index = {}
var cards_show = [ ]
var scenarios = []

var a_seq = 0
var b_seq = 0

/*
var message_map = {}
var msg_old = []
fs.readFileSync("tools/messages.txt", "utf-8").split("\n").forEach(line => {
	line = line.trimEnd()
	if (line === "")
		return
	if (line.startsWith("\t")) {
		line = line.trimStart()
		for (let old of msg_old)
			message_map[old] = line
		msg_old = []
	} else {
		msg_old.push(line)
	}
})
*/

function get_html_effect(effect) {
	effect = effect.replace(" If reduced to", "<br>If reduced to")
	effect = effect.replace(" Take dice", "<br>Take dice")
	effect = effect.replace(" (See", "<br>(See")
	return effect
}

function get_raw_effect(effect) {
	effect = effect.replace(/<br>/, " ")
	effect = effect.replace(/ \(See .*/, "")
	effect = effect.replace(/ Take dice.*/, "")
	effect = effect.replace(/ You CHOOSE the target./, "")
	effect = effect.replace(/ Ignores Link./i, "")
	effect = effect.replace(/ Warwick retires.*/, "")
	return effect
}

function remap(x) {
	if (x >= 42 && x <= 50) return (x - 42) + 51
	if (x >= 51) x += 9
	if (x >= 91 && x <= 99) return -1
	if (x >= 99) x -= 9
	if (x >= 216 && x <= 224) return x - 216 + 42
	if (x >= 224) x -= 5
	return x
}

let last_wing = null

var last_scen = null

var allcards = [
`<!doctype html>
<html lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<head>
<title>Table Battle Scenarios</title>
<link rel="stylesheet" href="/fonts/fonts.css">
<link rel="stylesheet" href="/table-battles/cards.css">
<style>
body{background-color:dimgray;color:whitesmoke;padding:20px;background-image:url(../images/background.png)}
.list{display:grid;grid-template-columns:min-content min-content;gap:20px;margin-bottom:40px}
a{text-decoration:none;color:black}
</style>
</head>
<body>
<div class="list">`
]

var result = [ ]

var scenario_html = {}

function flush_scenario_html() {
	scenario_html[last_scen] = result
	result = []
}

function nbsp_target(target) {
	return target
		.split(", ")
		.map(x=>x.replaceAll(" ", "\xa0"))
		.join(", ")
		.replaceAll("\xa0or\xa0", " or ")
		.replaceAll("\xa0OR\xa0", " OR ")
}

for (let c of card_records) {
	if (!c.number) {
		allcards.push(`</div><h1>${c.scenario}</h1><div class="list">`)
		if (result.length > 2) {
			flush_scenario_html()
		}
		last_wing = null
		continue
	}

	last_scen = c.scenario

	let html = []

	if ((c.wing === "blue" || c.wing === "dkblue") && (last_wing === "red" || last_wing === "pink"))
		html.push(`</div><div class="list">`)
	if ((last_wing === "blue" || last_wing === "dkblue") && (c.wing === "red" || c.wing === "pink"))
		html.push(`</div><div class="list">`)
	last_wing = c.wing

	if (!c.name)
		continue

	c.dice = c.dice.replace(")/(", "/")

	let card = {
		scenario: parseInt(c.scenario),
		number: c.number,
		name: c.name,
		wing: WING[c.wing],
		morale: 1,
	}

	if (c.alias)
		card.alias = c.alias

	let id = card_index[c.number] = cards.length

	cards.push(card)

	if (c.strength === "I") {
		card.special = 1
	}
	else if (c.strength === "II") {
		card.special = 2
	}
	else if (c.strength === "III") {
		card.special = 3
	}
	else if (c.strength === "IV") {
		card.special = 4
	}
	else if (c.strength === "V") {
		card.special = 5
	}
	else if (c.strength === "?") {
		card.special = -1
	}
	else if (c.strength.endsWith("*")) {
		card.strength = parseInt(c.strength)
		card.morale = 2
	}
	else if (c.strength.endsWith("-")) {
		card.strength = parseInt(c.strength)
		card.morale = 0
	}
	else {
		card.strength = parseInt(c.strength)
	}

	card.dice = c.dice
	card.actions = []

	let squeeze = 0
	if (c.action1_effect && c.action2_effect && (c.rule_text_2 || c.lore_text))
		squeeze = 1
	else if (SQUEEZE_BOXES.includes(c.number))
		squeeze = 1

	if (SQUEEZE_MARGINS.includes(c.number)) {
		card.squeeze = 1
		html.push(`<div class="formation card squeeze">`)
	} else {
		html.push(`<div class="formation card">`)
	}

	if (c.symbol)
		html.push(`<div class="name with_symbol ${c.wing}">${c.name}</div>`)
	else
		html.push(`<div class="name ${c.wing}">${c.name}</div>`)

	if (c.symbol === "inf") {
		card.infantry = 1
		html.push(`<div class="symbol infantry"></div>`)
	}
	if (c.symbol === "cav") {
		card.cavalry = 1
		html.push(`<div class="symbol cavalry"></div>`)
	}

	if (card.strength)
		html.push(`<div class="strength">${card.strength}</div>`)
	else
		html.push(`<div class="strength">${c.strength}</div>`)

	if (c.link === "LR") {
		card.link = [ id - 1, id + 1 ]
		html.push(`<div class="link left"></div>`)
		html.push(`<div class="link right"></div>`)
	} else if (c.link === "L") {
		html.push(`<div class="link left"></div>`)
		card.link = [ id - 1 ]
	} else if (c.link === "R") {
		html.push(`<div class="link right"></div>`)
		card.link = [ id + 1 ]
	}

	if (c.dice) {
		if (card.morale === 2)
			html.push(`<div class="star">&#x2605;</div>`)
		html.push(`<div class="dice_area">${c.dice}</div>`)
	}

	function make_action(type, requirement, target, effect, rule_text, short) {
		let a = { type }
		if (requirement) a.requirement = requirement
		if (target) a.target = target
		if (effect) a.effect_text = get_html_effect(effect)
		if (effect) a.effect = get_raw_effect(effect)
		if (rule_text) a.rule_text = rule_text
		if (short) a.short = 1
		return a
	}

	if (c.action1_type) {
		let short = c.action1_effect && (c.rule_text_1 || squeeze)
		card.actions.push(make_action(c.action1_type, c.action1_req, c.action1_target, c.action1_effect, c.action1_rule_text, short))
		html.push(`<div class="action_row">`)
		if (/Screen|Absorb|Counterattack/.test(c.action1_type))
			html.push(`<div class="action_type reaction">${c.action1_type}</div>`)
		else
			html.push(`<div class="action_type">${c.action1_type}</div>`)
		html.push(`<div class="action_requirement">${c.action1_req}</div>`)
		html.push(`<div class="action_target">${nbsp_target(c.action1_target)}</div>`)
		if (c.action1_effect) {
			c.action1_effect = get_html_effect(c.action1_effect)
			if (c.rule_text_1 || squeeze)
				html.push(`<div class="action_effect short">${c.action1_effect}</div>`)
			else
				html.push(`<div class="action_effect">${c.action1_effect}</div>`)
		}
		html.push(`</div>`)
	}

	if (c.rule_text_1) {
		card.rule_text_1 = c.rule_text_1
		html.push(`<div class="rule_text">${c.rule_text_1}</div>`)
	}

	if (c.action2_type || c.action2_effect) {
		let short = c.action2_effect && (c.rule_text_2 || squeeze)
		card.actions.push(make_action(c.action2_type, c.action2_req, c.action2_target, c.action2_effect, c.action2_rule_text, short))
		html.push(`<div class="action_row">`)
		if (/Screen|Absorb|Counterattack/.test(c.action2_type))
			html.push(`<div class="action_type reaction">${c.action2_type}</div>`)
		else
			html.push(`<div class="action_type">${c.action2_type}</div>`)
		html.push(`<div class="action_requirement">${c.action2_req}</div>`)
		html.push(`<div class="action_target">${nbsp_target(c.action2_target)}</div>`)
		if (c.action2_effect) {
			c.action2_effect = get_html_effect(c.action2_effect)
			if (c.rule_text_2 || squeeze)
				html.push(`<div class="action_effect short">${c.action2_effect}</div>`)
			else
				html.push(`<div class="action_effect">${c.action2_effect}</div>`)
		}
		html.push(`</div>`)
	}

	if (c.rule_text_2) {
		card.rule_text_2 = c.rule_text_2
		html.push(`<div class="rule_text">${c.rule_text_2}</div>`)
	}

	if (c.lore_text) {
		card.lore_text = c.lore_text
		html.push(`<div class="lore_text">${c.lore_text}</div>`)
	}

	if (c.rule) {
		card.rules = {}
		for (let rule of c.rule.split("; ")) {
			if (/=/.test(rule)) {
				let [ key, vals ] = rule.split("=")
				card.rules[key] = vals.split(",")
			} else {
				card.rules[rule] = 1
			}
		}
	}

	if (c.reserve) {
		if (c.reserve === "RETIRE, Ward") {
			card.retire = 1
			card.reserve = [ "Ward" ]
		}
		else if (c.reserve === "RETIRE, PURSUIT") {
			card.retire = 1
			card.pursuit = 1
		}
		else if (c.reserve === "RETIRE")
			card.retire = 1
		else if (c.reserve === "PURSUIT")
			card.pursuit = 1
		else if (c.reserve === "Commanded" || c.reserve === "See Above" || c.reserve === "Special Rule")
			card.reserve = c.reserve
		else
			card.reserve = c.reserve.split(" or ")

		if (card.retire && card.reserve)
			html.push(`<div class="reserve">RETIRE; RESERVE (${card.reserve.join(", ")})</div>`)
		else if (card.retire && card.pursuit)
			html.push(`<div class="reserve">RETIRE, PURSUIT</div>`)
		else if (card.retire)
			html.push(`<div class="reserve">RETIRE</div>`)
		else if (card.pursuit)
			html.push(`<div class="reserve">PURSUIT</div>`)
		else
			html.push(`<div class="reserve">IN RESERVE (${c.reserve})</div>`)
	}

	html.push(`<div class="number">${c.number}</div>`)
	html.push(`<div class="extra">${WING_ICON[card.wing]}</div>`)

	html.push(`</div>`)

	for (let line of html) {
		result.push(line)
		allcards.push(line)
	}

	if (c.number.endsWith("A"))
		allcards.push(`<img class="ref" height="338" src="/table-battles/ref2/sliced/card_A${remap(a_seq++)}.jpg">`)
	else
		allcards.push(`<img class="ref" height="338" src="/table-battles/ref2/sliced/card_B${remap(b_seq++)}.jpg">`)
}

flush_scenario_html()

function find_card(scenario, name) {
	name = name.replace("*", "")
	name = name.replace(" (Voluntary)", "")
	for (let c of cards)
		if (c.scenario === scenario && (c.name === name || c.alias === name))
			return card_index[c.number]
	throw new Error("CARD NOT FOUND: " + scenario + " " + name)
}

function find_enemy_cards(scenario, wing) {
	let w1, w2
	if (wing === 0 || wing === 1)
		w1 = 2, w2 = 3
	if (wing === 2 || wing === 3)
		w1 = 0, w2 = 1
	let list = []
	for (let c of cards)
		if (c.scenario === scenario && (c.wing === w1 || c.wing === w2))
			list.push(card_index[c.number])
	return list
}

function find_friendly_cards(scenario, wing) {
	let w1, w2
	if (wing === 0 || wing === 1)
		w1 = 0, w2 = 1
	if (wing === 2 || wing === 3)
		w1 = 2, w2 = 3
	let list = []
	for (let c of cards)
		if (c.scenario === scenario && (c.wing === w1 || c.wing === w2))
			list.push(card_index[c.number])
	return list
}

function find_wing_cards(scenario, wing) {
	let list = []
	for (let c of cards)
		if (c.scenario === scenario && c.wing === wing)
			list.push(card_index[c.number])
	return list
}

/* process action and reserve targets */
function process_card(c, ix) {
	for (let a of c.actions) {
		if (a.target) {
			let tname = a.target.replace(" out of reserve", "")

			if (tname === "Any enemy attack" || tname === "Any enemy formation" || tname === "Any enemy attacking it")
				a.target_list = find_enemy_cards(c.scenario, c.wing)
			else if (tname === "Any friendly formation")
				a.target_list = find_friendly_cards(c.scenario, c.wing)
			else if (tname === "Any friendly Pink formation")
				a.target_list = find_wing_cards(c.scenario, WING.pink)
			else if (tname === "Any other Pink formation")
				a.target_list = find_wing_cards(c.scenario, WING.pink).filter(x => x !== c)
			else if (tname === "Any Red formation")
				a.target_list = find_wing_cards(c.scenario, WING.red)
			else if (tname === "Any Pink formation")
				a.target_list = find_wing_cards(c.scenario, WING.pink)
			else if (tname === "Any Blue formation")
				a.target_list = find_wing_cards(c.scenario, WING.blue)
			else if (tname === "Any Dark Blue formation")
				a.target_list = find_wing_cards(c.scenario, WING.dkblue)
			else if (tname.startsWith("Any attack on "))
				a.target_list = tname.replace("Any attack on ", "").split(" or ").map(name => find_card(c.scenario, name))
			else if (tname === "Any friendly but Little Round Top")
				a.target_list = find_friendly_cards(c.scenario, c.wing).filter(x => x !== find_card(c.scenario, "Little Round Top"))
			else if (tname === 'Activate "Retreat to Nivelles"')
				a.target_list = null
			else if (tname === "The Fog Lifts...")
				a.target_list = null
			else if (tname === "See Below")
				a.target_list = null
			else
				a.target_list = tname.split(/, | OR | or | and /).map(name => find_card(c.scenario, name))
		}

		if (a.type === "Absorb") {
			a.target_list = a.target_list.filter(x => x !== ix) // never absorb for self
		}

		if (a.type === "Screen")
			a.choice = 1
		else if (/, /.test(a.target) || !a.target_list || a.target_list.length < 2)
			a.choice = 0
		else
			a.choice = 1
	}

	// Hohenfriedberg invisible charles last target in list!
	if (c.number === "267A" || c.number === "268A" || c.number === "269A")
		c.actions[0].target_list.push(find_card(c.scenario, "Charles"))

	if (c.rules) {
		for (let key in c.rules) {
			let val = c.rules[key]
			if (Array.isArray(val))
				c.rules[key] = val.map(number => card_index[number])
		}
	}
	if (c.pursuit) {
		if (c.actions[0].type !== "Attack" && c.actions[0].type !== "Counterattack")
			throw new Error("PURSUIT without Attack or Counterattack as first action")
		if (c.actions[0].target_list.length !== 1)
			throw new Error("PURSUIT with more than one target!")
		c.pursuit = c.actions[0].target_list[0]
	}
	if (Array.isArray(c.reserve))
		c.reserve = c.reserve.map(name => find_card(c.scenario, name))
}

let failed = false
cards.forEach((c, ix) => {
	try {
		process_card(c, ix)
	} catch (err) {
		console.log(err)
		failed = true
	}
})

fs.writeFileSync("info/ref.html", allcards.join("\n"))

result = [
`<!doctype html>
<html lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<head>
<title>Table Battle Scenarios</title>
<link rel="stylesheet" href="/fonts/fonts.css">
<link rel="stylesheet" href="/table-battles/cards.css">
<style>
body{background-color:dimgray;color:whitesmoke;padding:20px;background-image:url(../images/background.png)}
.list{display:flex;flex-wrap:wrap;gap:20px;margin-bottom:40px}
a{text-decoration:none;color:black}
</style>
</head>
<body>
<div class="list">`
]

function parse_cards(text) {
	let out = []
	let list = text.split(",")
	for (let range of list) {
		let [a, b] = range.split("-")
		a = card_index[a]
		b = card_index[b]
		if (a === undefined || b === undefined)
			throw new Error("MISSING CARDS FOR " + text)
		for (let i = a; i <= b; ++i)
			out.push(i)
	}
	return out
}

let last_exp = null
for (let s of scenario_records) {
	if (!s.name)
		continue
	if (last_exp !== s.expansion) {
		result.push(`</div><h1>${s.expansion}</h1><div class="list">`)
		last_exp = s.expansion
	}
	try {
		scenarios.push({
			number: parseInt(s.number),
			expansion: s.expansion,
			name: s.name,
			date: s.date,
			players: [
				{ name: s.player1, cards: parse_cards(s.cards1), morale: parseInt(s.morale1), tactical: parseInt(s.tactical1) || undefined },
				{ name: s.player2, cards: parse_cards(s.cards2), morale: parseInt(s.morale2), tactical: parseInt(s.tactical2) || undefined },
			],
			rule: s.rule || undefined,
			rule_text: s.rule_text || undefined,
			lore_text: s.lore_text || undefined,
			wikipedia: s.wikipedia,
		})
		var html =
`<div id="scenario_${s.number}" class="scenario card">
<div class="scenario_title">
<div class="battle_name">${s.name}</div>
<div class="battle_date">${s.date}</div>
</div>
<div class="scenario_player">
<div class="scenario_player_name">${s.player1}</div>
<div class="scenario_line">Cards ${s.cards1}</div>
<div class="scenario_line">Morale: ${s.morale1}</div>
<div class="scenario_line">${s.tactical1 ? "Tactical Victory: " + s.tactical1 : ""}</div>
</div>
<div class="scenario_player">
<div class="scenario_player_name">${s.player2}</div>
<div class="scenario_line">Cards ${s.cards2}</div>
<div class="scenario_line">Morale: ${s.morale2}</div>
<div class="scenario_line">${s.name !== "Fleurus" && s.tactical2 ? "Tactical Victory: " + s.tactical2 : ""}</div>
</div>
<div class="rule_text">${s.rule_text}</div>
<div class="lore_text">${s.lore_text}</div>
<div class="number">${s.number}</div>
</div>`

		scenario_html[s.number].unshift(`</div><div class="list">`)
		scenario_html[s.number].unshift(html)
		scenario_html[s.number].unshift(
`<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${s.number} - ${s.name}</title>
<link rel="stylesheet" href="/fonts/fonts.css">
<link rel="stylesheet" href="/table-battles/cards.css">
<style>
body{background-color:dimgray;color:whitesmoke;padding:20px;background-image:url(../images/background.png)}
.list{display:flex;flex-wrap:wrap;gap:20px;margin-bottom:40px}
</style>
</head>
<body>
<h1>${s.number} - ${s.name}</h1>
<div class="list">`)

		fs.writeFileSync(`info/s_${s.number}.html`, scenario_html[s.number].join("\n"))
		result.push(`<a href="/table-battles/info/s_${s.number}.html">`, html, '</a>')
		// result.push(`<img src="/table-battles/paintings/${s.name.toLowerCase().replaceAll(" ", "_")}.jpg">`)
	} catch (err) {
		console.log(err)
	}
}

fs.writeFileSync("info/scenarios.html", result.join("\n"))

result = []
result.push("const data = {")
result.push("scenarios: [")
for (let row of scenarios) result.push(JSON.stringify(row) + ",")
result.push("],\ncards: [")
for (let row of cards) result.push(JSON.stringify(row) + ",")
result.push("],\n}")
result.push("if (typeof module!=='undefined') module.exports = data")
fs.writeFileSync("data.js", result.join("\n"))