const express = require('express')
const axios = require('axios')
var http = require('http');
var https = require('https');
const fs = require('fs');

const sh = require('secrethash');

var key = fs.readFileSync('./projectdivar.com/privkey.pem');
var cert = fs.readFileSync('./projectdivar.com/cert.pem');
var options = {
	key: key,
	cert: cert
};

const app = express()

var server = https.createServer(options, app);
const port = 4505
server.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
const bodyParser = require('body-parser')
const { json } = require('body-parser')
const moment = require('moment');
const Pool = require('pg').Pool
app.use(bodyParser.json())
app.use(
	bodyParser.urlencoded({
		extended: true,
	})
)


let allowCrossDomain = function (req, res, next) {
	res.header('Access-Control-Allow-Origin', "*");
	res.header('Access-Control-Allow-Headers', "*");
	res.header('Access-Control-Allow-Methods', "*");
	next();
}
app.use(allowCrossDomain);

var db =
	new Pool({
		user: 'postgres',
		password: '',
		host: 'postgres',
		database: 'sigcrafting',
		port: 5432,
	})

app.get('/', async (req, res) => {
	res.status(200).send('BUN is love, BUN is life.')
})

app.get('/getData', (req, res) => {
	db.query('select * from crafting_list order by id asc')
		.then((data) => {
			if (data.rows.length > 0) {
				res.status(200).json(data.rows)
			} else {
				res.status(204).send("No data")
			}
		})
		.catch((err) => {
			res.status(500).send(err.message)
		})
})

app.get('/getNotifications', (req, res) => {
	db.query('select * from audit_log where date>$1 order by id asc limit 10', [req.query.date])
		.then((data) => {
			res.status(200).json(data.rows)
		})
		.catch((err) => {
			console.log(err)
			res.status(500).send(err.message)
		})
})

app.get('/lastUpdate', (req, res) => {
	db.query("select * from site_data limit 1")
		.then((data) => {
			res.status(200).json(data.rows)
		})
		.catch((err) => {
			res.status(500).send(err.message)
		})
})

app.post("/updateItem", (req, res) => {
	var itemIcon = ""
	db.query("update crafting_list set obtained=$1 where id=$2 returning *", [req.body.obtained, req.body.id])
		.then((data) => {
			itemIcon = "https://xivapi.com" + data.rows[0].icon
			return db.query("update site_data set last_modified=$1", [req.body.last_modified])
		})
		.then((data) => {
			return axios.post(process.env.DISCORD_WEBHOOK, {
				embeds: [{
					author: {
						name: req.body.item_name,
						icon_url: itemIcon
					},
					color: req.body.obtained == req.body.required ? 32768 : Number(req.body.obtained) > 0 ? 20680 : 2172201,
					description: "**" + req.body.username + "** " + (req.body.operation === "FINISH" ? " has finished " + (req.body.finalcraft === true ? "crafting " : "collecting ") + req.body.required + " __" + req.body.item_name + "__!" :
						req.body.operation === "INCREASE" ? " has collected " + req.body.obtained + " / " + req.body.required + " __" + req.body.item_name + "__ (+" + (req.body.obtained - req.body.previous_amt) + ")"
							: " has set __" + req.body.item_name + "__  to " + req.body.obtained + " / " + req.body.required) + "\n\n[Sig Planner - Sig crafts all the things](http://projectdivar.com:3001)",
					footer: {
						"text": "Progress: " + ((req.body.itemCount + req.body.obtained - req.body.previous_amt) / req.body.totalItemCount * 100).toFixed(2) + "%  (" + (req.body.itemCount + req.body.obtained - req.body.previous_amt) + "/" + req.body.totalItemCount + ")"
					}
				}]
			})
		})
		.then((data) => {
			return db.query("insert into audit_log(username,obtained,required,item_name,operation,date,previous_amt) values($1,$2,$3,$4,$5,$6,$7)", [req.body.username, req.body.obtained, req.body.required, req.body.item_name, req.body.operation === "FINISH" && req.body.finalcraft === true ? "FINISH_CRAFT" : req.body.operation, req.body.last_modified, req.body.previous_amt])
		})
		.then((data) => {
			res.status(200).send("Yay!")
		})
		.catch((err) => {
			console.log(err.message)
			res.status(500).send(err.message)
		})
})

app.post("/updateTimer", (req, res) => {
	if (req.body.timer_start !== null && req.body.timer_end !== null && req.body.timer_start !== undefined && req.body.timer_end !== undefined) {
		var splitter = req.body.timer_start.split(",")
		var splitter2 = req.body.timer_end.split(",")
		for (t of splitter) {
			if (t == "") continue;
			if (t.split(":").length != 2 || (t.split(":").length == 2 && (isNaN(t.split(":")[0]) || isNaN(t.split(":")[1])))) {
				res.status(500).send("Invalid input!")
				return
			}
		}
		for (t of splitter2) {
			if (t == "") continue;
			if (t.split(":").length != 2 || (t.split(":").length == 2 && (isNaN(t.split(":")[0]) || isNaN(t.split(":")[1])))) {
				console.log(t)
				res.status(500).send("Invalid input!")
				return
			}
		}
		db.query("update crafting_list set timer_start=$1,timer_end=$2 where id=$3 returning *", [req.body.timer_start, req.body.timer_end, req.body.id])
			.then((data) => {
				itemIcon = "https://xivapi.com" + data.rows[0].icon
				return db.query("update site_data set last_modified=$1", [req.body.last_modified])
			})
			.then((data) => {
				res.status(200).send("Yay!")
			})
			.catch((err) => {
				console.log(err.message)
				res.status(500).send(err.message)
			})
	} else {
		res.status(500).send("Invalid input!")
	}
})

app.post('/setItem', async (req, res) => {
	await db.query('select * from crafting_list where itemid=$1', [req.body.itemid])
		.then((data) => {
			if (data.rows.length == 0) {
				db.query('insert into crafting_list(itemid,name,obtained,required,icon) values($1,$2,$3,$4,$5)', [req.body.itemid, req.body.name, req.body.obtained, req.body.required, req.body.icon])
					.then((data) => {
						res.status(200).send("Yay!")
					})
					.catch((err) => {
						res.status(500).send(err.message)
					})
			} else {
				db.query('update crafting_list set required=$1 where itemid=$2', [Number(data.rows[0].required) + Number(req.body.required), req.body.itemid])
					.then((data) => {
						res.status(200).send("Yayay!")
					})
					.catch((err) => {
						res.status(500).send(err.message)
					})
			}
		})
})


app.post('/addItem', async (req, res) => {
	await db.query('select * from crafting_list where itemid=$1', [req.body.itemid])
		.then((data) => {
			if (data.rows.length > 0) {
				db.query('update crafting_list set obtained=$1 where itemid=$2', [Math.min(data.rows[0].required, Number(data.rows[0].obtained) + Number(req.body.obtained)), req.body.itemid])
					.then((data) => {
						res.status(200).send("AYAYA")
					})
					.catch((err) => {
						res.status(500).send(err.message)
					})
			} else {
				res.status(200).send("Nothing to do!")
			}
		})
})

function ConvertIssues(str, repoURL) {
	str += ' ' //Hack to fix issues with not finding a space after links.
	var split = str.split("Issue #");
	for (var i = 0; i < split.length - 1; i++) {
		split[i] += "[Issue #"
		var spaceLocation = split[i + 1].indexOf(' ');
		var spaceSubStr = Number(split[i + 1].substr(0, spaceLocation));
		if (Number.isInteger(spaceSubStr)) {
			split[i + 1] = spaceSubStr + "](" + repoURL + "/issues/" + spaceSubStr + ") " + split[i + 1].substr(spaceLocation + 1)
		}
	}
	var split2 = split.join("").split("Issue#")
	console.log(split2)
	for (var i = 0; i < split2.length - 1; i++) {
		split2[i] += "[Issue#"
		var spaceLocation = split[i + 1].indexOf(' ');
		var spaceSubStr = Number(split[i + 1].substr(0, spaceLocation));
		if (Number.isInteger(spaceSubStr)) {
			split[i + 1] = spaceSubStr + "](" + repoURL + "/issues/" + spaceSubStr + ") " + split[i + 1].substr(spaceLocation + 1)
		}
	}
	return split2.join("");
}

function ParseMentions(str) {
	//@quapsel: 155789951571591168
	//@sigonasr2: 176012829076226048
	return str.replaceAll("@Quapsel", "<@155789951571591168>").replaceAll("@sigonasr2", "<@176012829076226048>")
}

var embedItems = [];
function ParseAttachments(str) {
	var stage = 0;
	var backTickRepeatCount = 0;
	var backTicksEnabled = false;
	var isImage = false;
	var accumulatedLink = "";
	for (var i = 0; i < str.length; i++) {
		//If at any time we find ```, we continue until they close.
		if (str[i] == '`') {
			backTickRepeatCount++;
			if (backTickRepeatCount == 3) {
				backTickRepeatCount = 0;
				backTicksEnabled = !backTicksEnabled;
			}
			continue;
		} else {
			backTickRepeatCount = 0;
		}
		if (backTicksEnabled) {
			continue; //As long as we are in back tick mode, we don't care what is posted.
		}
		switch (stage) {
			case 0: {
				//In stage 0 we look for [.
				if (str[i] == '[') {
					if (i > 0 && str[i - 1] == '!') {
						isImage = true;
					} else {
						isImage = false;
					}
					stage++;
				}
			} break;
			case 1: {
				//In stage 1 we look for ].
				if (str[i] == ']') {
					stage++;
				}
			} break;
			case 2: {
				//In stage 2 the next character should be (. If it's not, reset.
				if (str[i] == '(') {
					stage++;
				} else {
					stage = 0;
				}
			} break;
			case 3: {
				//In stage 3, we accumulate what's inside and look for ).
				if (str[i] == ')') {
					//We're done! We have a new embed.
					if (accumulatedLink.startsWith("http")) {
						if (isImage) {
							embedItems = [...embedItems, { image: { url: accumulatedLink } }]
						} else {
							embedItems = [...embedItems, { url: accumulatedLink }]
						}
					} else {
						if (isImage) {
							embedItems = [...embedItems, { image: { url: "http://sig.projectdivar.com/" + accumulatedLink } }]
						} else {
							embedItems = [...embedItems, { url: "http://sig.projectdivar.com/" + accumulatedLink }]
						}
					}
					accumulatedLink = ""
					isImage = false;
					stage = 0;
					break;
				} else {
					accumulatedLink += str[i];
				}
			} break;
		}
	}
	return str
}

embeds = []
setInterval(() => {
	if (embeds.length > 0) {
		axios.post(process.env.GITEA_WEBHOOK, embeds.shift());
	}
}, 1000);

app.post("/postUpdate", (req, res) => {
	res.status(200).send("Thank you!")
	embedItems = []
	if (req.body.action) {
		switch (req.body.action) {
			case "opened": {
				embedItems = [{
					author: {
						name: "Issue #" + req.body.number + " opened by " + req.body?.issue?.user?.username,
						icon_url: req.body.issue.user.avatar_url
					},
					color: 11731199,
					description: "**" + req.body.issue.title + ":**\n\n" + ConvertIssues(ParseAttachments(ParseMentions(req.body.issue.body)), req.body.repository?.html_url) + "\n\n[Link to Issue](" + req.body.issue?.html_url + ")",
				}, ...embedItems];
				embeds.push({ embeds: embedItems });
			} break;
			case "reopened": {
				embeds.push({
					embeds: [{
						author: {
							name: "Issue #" + req.body.number + " re-opened by " + req.body.issue.user.username,
							icon_url: req.body.issue.user.avatar_url
						},
						color: 13789695,
						description: "**" + req.body.issue.title + ":**\n\n" + ConvertIssues(req.body.issue.body, req.body.repository?.html_url) + "\n\n[Link to Issue](" + req.body.issue?.html_url + ")",
					}]
				});
			} break;
			case "assigned": {
				var assignedList = ""
				for (assignee of req.body.issue.assignees) {
					if (assignedList.length == 0) {
						assignedList += assignee.username
					} else {
						assignedList += "," + assignee.username
					}
				}
				embeds.push({
					embeds: [{
						author: {
							name: "Assigned users to Issue #" + req.body.number,
							icon_url: req.body.issue.user.avatar_url
						},
						color: 50363,
						description: "Assigned **" + assignedList + "** to Issue **" + req.body.issue.title + "**\n\n[Link to Issue](" + req.body.issue.html_url + ")",
					}]
				});
			} break;
			case "label_updated": {
				var labelsList = ""
				for (label of req.body.issue.labels) {
					if (labelsList.length == 0) {
						labelsList += "- **" + label.name + "**"
					} else {
						labelsList += "\n- **" + label.name + "**"
					}
				}
				embeds.push({
					embeds: [{
						author: {
							name: "Assigned labels to Issue #" + req.body.number,
							icon_url: req.body.issue.user.avatar_url
						},
						color: 365568,
						description: "Labels set for Issue **" + req.body.issue.title + "**:\n" + labelsList + "\n\n[Link to Issue](" + req.body.issue.html_url + ")",
					}]
				})
			} break;
			case "created": {
				embeds.push({
					embeds: [{
						author: {
							name: "Comment posted on Issue #" + req.body.issue.number,
							icon_url: req.body.comment.user.avatar_url
						},
						color: 11731199,
						description: "__**" + req.body.issue.title + "**__\nCommented by **" + req.body.comment.user.username + ":**\n" + ConvertIssues(ParseAttachments(ParseMentions(req.body.comment.body)), req.body.repository.html_url) + "\n\n[Link to Comment](" + req.body.comment.html_url + ")",
					}]
				})
			} break;
			case "edited": {
				if (req.body.comment) {
					embedItems = [{
						author: {
							name: "Comment edited on Issue #" + req.body.issue.number,
							icon_url: req.body.comment.user.avatar_url
						},
						color: 11731199,
						description: "__**" + req.body.issue.title + "**__\nCommented by **" + req.body.comment.user.username + ":**\n" + ConvertIssues(ParseAttachments(ParseMentions(req.body.comment.body)), req.body.repository.html_url) + "\n\n[Link to Comment](" + req.body.comment.html_url + ")",
					}, ...embedItems]
					embeds.push({ embeds: embedItems })
				} else {
					embedItems = [{
						author: {
							name: "Edit on Issue #" + req.body.issue.number,
							icon_url: req.body.issue.user.avatar_url
						},
						color: 11731199,
						description: "__**" + req.body.issue.title + "**__\nEdited by **" + req.body.issue.user.username + ":**\n" + ConvertIssues(ParseAttachments(ParseMentions(req.body.issue.body)), req.body.repository.html_url) + "\n\n[Link to Issue](" + req.body.issue.html_url + ")",
					}, ...embedItems]
					embeds.push({ embeds: embedItems });
				}
			} break;
			case "deleted": {
				embeds.push({
					embeds: [{
						author: {
							name: "Comment deleted on Issue #" + req.body.issue.number,
							icon_url: req.body.comment.user.avatar_url
						},
						color: 11731199,
						description: "__**" + req.body.issue.title + "**__\nCommented by **" + req.body.comment.user.username + ":**\n~~" + ConvertIssues(req.body.comment.body, req.body.repository.html_url) + "~~\n\n[Link to Comment](" + req.body.comment.html_url + ")",
					}]
				})
			} break;
			case "closed": {
				embeds.push({
					embeds: [{
						author: {
							name: "Issue #" + req.body.number + " closed by " + req.body.issue.user.username,
							icon_url: req.body.issue.user.avatar_url
						},
						color: 9502805,
						description: "**" + req.body.issue.title + ":**\n\n" + ConvertIssues(req.body.issue.body, req.body.repository.html_url) + "\n\n[Link to Issue](" + req.body.issue.html_url + ")",
					}]
				})
			} break;
			default: {
				console.log("Unknown action " + req.body.action + ". Ignoring.")
			}
		}
	} else
		if (req.body.ref) {
			for (var commit of req.body.commits) {
				var filesAdded = commit.added.length
				var filesRemoved = commit.removed.length
				var filesModified = commit.modified.length
				axios.post(process.env.GITEA_WEBHOOK, {
					embeds: [{
						author: {
							name: commit.author.username + " has pushed a new commit",
							icon_url: "http://sig.projectdivar.com/assets/update.png"
						},
						color: 17663,
						description: "**Commit ID " + commit.id + "**\n\n" + ConvertIssues(commit.message, req.body.repository.html_url) + "\n" + (filesAdded > 0 ? "\n" + filesAdded + " file" + (filesAdded == 1 ? "" : "s") + " added" : "") + (filesRemoved > 0 ? "\n" + filesRemoved + " file" + (filesRemoved == 1 ? "" : "s") + " removed" : "") + (filesModified > 0 ? "\n" + filesModified + " file" + (filesModified == 1 ? "" : "s") + " modified" : "") + "\n\n[Link to Commit](" + commit.url + ")",
					}]
				})
			}
		} else {
			console.log("Unknown webhook incoming. Ignoring.")
		}
	/*
	return axios.post(process.env.DISCORD_WEBHOOK,{embeds:[{
		author:{
			name:req.body.item_name,
			icon_url:itemIcon
		},
		color:req.body.obtained==req.body.required?32768:Number(req.body.obtained)>0?20680:2172201,
		description:"**"+req.body.username+"** "+(req.body.operation==="FINISH"?" has finished "+(req.body.finalcraft===true?"crafting ":"collecting ")+req.body.required+" __"+req.body.item_name+"__!":
	req.body.operation==="INCREASE"?" has collected "+req.body.obtained+" / "+req.body.required+" __"+req.body.item_name+"__ (+"+(req.body.obtained-req.body.previous_amt)+")"
	:" has set __"+req.body.item_name+"__  to "+req.body.obtained+" / "+req.body.required)+"\n\n[Sig Planner - Sig crafts all the things](http://projectdivar.com:3001)",
	footer:{
		"text":"Progress: "+((req.body.itemCount+req.body.obtained-req.body.previous_amt)/req.body.totalItemCount*100).toFixed(2)+"%  ("+(req.body.itemCount+req.body.obtained-req.body.previous_amt)+"/"+req.body.totalItemCount+")"
	}
	}]
})*/
})

var runInventoryScan = async () => {
	for (var item of myInv) {
		const it = item
		await db.query('select * from crafting_list where itemid=$1', [item.itemId])
			.then(async (data) => {
				for (var row of data.rows) {
					if (row.required - row.obtained <= it.quantity) {
						await db.query('update crafting_list set obtained=$1 where itemid=$2', [row.required, it.itemId])
							.catch((err) => {
								console.log(err.message)
							})
					} else {
						await db.query('update crafting_list set obtained=$1 where itemid=$2', [row.obtained + it.quantity, it.itemId])
							.catch((err) => {
								console.log(err.message)
							})
						break;
					}
				}
			})
			.catch((err) => {
				console.log(err.message)
			})
	}
}

app.post("/AiL", function (req, res) {
	var username = decodeURI(req.body.username)
	var operation = decodeURI(req.body.operation)
	var checksum = decodeURI(req.body.checksum)
	var data = decodeURI(req.body.data)
	const saveDir = "files/AiLsaves/";
	if (username && operation && checksum && data) {
		if (username.length <= 24 &&
			(operation === "GET_LOAD_FILES" || operation === "GET_FILE" || operation === "SAVE_FILE" || operation === "SAVE_METADATA_FILE") &&
			data.length <= 1000000 &&
			Number(checksum) === username.length * 8 + data.length * 2 + operation.length) {
			//Checksum: Length of username*8+Length of data*2+Length of operation
			if (!fs.existsSync(`${saveDir + username}`)) {
				fs.mkdirSync(`${saveDir + username}`);
			}
			switch (operation) {
				case "GET_LOAD_FILES": {
					if (fs.existsSync(`${saveDir + username}/metadata.dat`)) {
						res.status(200).send(fs.readFileSync(`${saveDir + username}/metadata.dat`));
					} else {
						fs.writeFileSync(`${saveDir + username}/metadata.dat`, "\n");
						res.status(200).send(fs.readFileSync(`${saveDir + username}/metadata.dat`));
					}
				} break;
				case "GET_FILE": {
					if (fs.existsSync(`${saveDir + username}/save.${data.padStart(4, '0')}`)) {
						res.status(200).send(fs.readFileSync(`${saveDir + username}/save.${data.padStart(4, '0')}`));
					} else {
						res.status(404).send("Not Found!");
					}
				} break;
				case "SAVE_FILE": {
					var fileData = data.split("|");
					var fileNumb = fileData[0];
					var saveFileData = fileData[1];

					fs.writeFileSync(`${saveDir + username}/save.${fileNumb.padStart(4, '0')}`, saveFileData);
					res.status(200).send("Saved!");
				} break;
				case "SAVE_METADATA_FILE": {
					fs.writeFileSync(`${saveDir + username}/metadata.dat`, data);
					res.status(200).send("Saved!");
				} break;
				default: {
					res.status(418).send('I\'m definitely a teapot.');
				}
			}
		} else {
			res.status(418).send('I\'m definitely a teapot.');
		}
	} else {
		res.status(400).send('Invalid input!');
	}
});

//runInventoryScan()

//console.log(process.env.DISCORD_WEBHOOK)