const Busboy = require('busboy');
const { parse } = require('csv-parse/sync');

async function middleware(req, res, next) {
	const contentType = req.headers['content-type'] || '';
	let csvText = null;
	let filename = null;

	if (req.params.filename && contentType.startsWith('text/csv')) {
		csvText = typeof req.body === 'string' ? req.body : req.body.toString('utf8');
		filename = req.params.filename;
		processCsv();
	} else if (contentType.startsWith('multipart/form-data')) {
		const busboy = Busboy({ headers: req.headers });
		let found = false;
		busboy.on('file', (name, file, info) => {
			if (found) {
				file.resume();
				return;
			}
			if (info.mimeType === 'text/csv') {
				found = true;
				filename = info.filename || 'unnamed.csv';
				csvText = '';
				file.setEncoding('utf8');
				file.on('data', (data) => { csvText += data; });
				file.on('end', () => {});
			} else {
				file.resume();
			}
		});
		busboy.on('field', () => {}); // Ignore fields
		busboy.on('finish', () => {
			if (!found) {
				return next();
			}
			processCsv();
		});
		req.pipe(busboy);
		return;
	} else {
		return next();
	}

	function processCsv() {
		let records;
		try {
			records = parse(csvText, {
				relax_quotes: true,
				quote: '"',
				escape: '"',
				skip_empty_lines: true,
				trim: true
			});
		} catch (e) {
			return res.status(400).json({ error: 'Invalid CSV' });
		}
		if (!records.length) {
			return res.status(400).json({ error: 'Empty CSV' });
		}
		const headers = records[0].map(h => h.toLowerCase().trim());
		const rows = records.slice(1);
		let lastDate = null;
		let lastTime = null;
		const currentDate = new Date().toISOString().slice(0, 10);
		const currentTime = new Date().toISOString().slice(11, 19);
		const events = [];
		for (let row of rows) {
			let object = { labels: [] };
			for (let k = 0; k < headers.length; k++) {
				let key = headers[k];
				let val = row[k] ? row[k].trim() : '';
				if (!key) continue;
				if (['remarks', 'event', 'comment', 'comments', 'text'].includes(key)) {
					object.remarks = val;
				} else if (key === 'label') {
					if (val) object.labels.push(val);
				} else if (key === 'labels') {
					if (val) object.labels.push(...val.split(';').map(l => l.trim()).filter(l => l));
				} else if (key === 'sequence' || key === 'seq') {
					if (val) object.sequence = Number(val);
				} else if (['point', 'shot', 'shotpoint'].includes(key)) {
					if (val) object.point = Number(val);
				} else if (key === 'date') {
					object.date = val;
				} else if (key === 'time') {
					object.time = val;
				} else if (key === 'timestamp') {
					object.timestamp = val;
				} else if (key === 'latitude') {
					object.latitude = parseFloat(val);
				} else if (key === 'longitude') {
					object.longitude = parseFloat(val);
				}
			}
			if (!object.remarks) continue;
			let useSeqPoint = Number.isFinite(object.sequence) && Number.isFinite(object.point);
			let tstamp = null;
			if (!useSeqPoint) {
				if (object.timestamp) {
					tstamp = new Date(object.timestamp);
				}
				if (!tstamp || isNaN(tstamp.getTime())) {
					let dateStr = object.date || lastDate || currentDate;
					let timeStr = object.time || lastTime || currentTime;
					if (timeStr.length === 5) timeStr += ':00';
					let full = `${dateStr}T${timeStr}.000Z`;
					tstamp = new Date(full);
					if (isNaN(tstamp.getTime())) continue;
				}
				if (object.date) lastDate = object.date;
				if (object.time) lastTime = object.time;
			}
			let event = {
				remarks: object.remarks,
				labels: object.labels,
				meta: {
					author: "*CSVImport*",
					"*CSVImport*": {
						filename,
						tstamp: new Date().toISOString()
					}
				}
			};
			if (!isNaN(object.latitude) && !isNaN(object.longitude)) {
				event.meta.geometry = {
					type: "Point",
					coordinates: [object.longitude, object.latitude]
				};
			}
			if (useSeqPoint) {
				event.sequence = object.sequence;
				event.point = object.point;
			} else if (tstamp) {
				event.tstamp = tstamp.toISOString();
			} else {
				continue;
			}
			events.push(event);
		}
		req.body = events;
		next();
	}
}

module.exports = middleware;
