import {setupPopover} from './popover';

const roiCache: Record<string, Promise<{lastModified: Date, profits: Profit[]}>> = {};
async function getROI(cx: string) {
	const response = await fetch(`/roi_${cx.toLowerCase()}.json`);
	const lastModified = new Date(response.headers.get('last-modified')!);
	const profits = await response.json();
	return {lastModified, profits};
}

const lowVolume = document.querySelector('input#low-volume') as HTMLInputElement;

const cxSelect = document.querySelector('select#cx') as HTMLSelectElement;
const expertise = {
	AGRICULTURE: 'agri',
	CHEMISTRY: 'chem',
	CONSTRUCTION: 'const',
	ELECTRONICS: 'elec',
	FOOD_INDUSTRIES: 'food ind',
	FUEL_REFINING: 'fuel',
	MANUFACTURING: 'mfg',
	METALLURGY: 'metal',
	RESOURCE_EXTRACTION: 'res ext',
} as const;
const expertiseSelect = document.querySelector('select#expertise') as HTMLSelectElement;
for (const key of Object.keys(expertise)) {
	const option = document.createElement('option');
	option.value = key;
	option.textContent = key.replace('_', ' ').toLowerCase();
	expertiseSelect.appendChild(option);
}
const buildingSelect = document.querySelector('select#building') as HTMLSelectElement;

const formatDecimal = new Intl.NumberFormat(undefined,
		{maximumFractionDigits: 2, maximumSignificantDigits: 6, roundingPriority: 'lessPrecision'}).format;
const formatWhole = new Intl.NumberFormat(undefined, {maximumFractionDigits: 0}).format;

async function render() {
	const tbody = document.querySelector('tbody')!;
	tbody.innerHTML = '';

	const cx = cxSelect.value;
	if (!roiCache[cx])
		roiCache[cx] = getROI(cx);
	const {lastModified, profits} = await roiCache[cx];

	const buildingTickers = new Set(profits.map(p => p.building));
	const buildings: {ticker: string, expertise: keyof typeof expertise}[] = Array.from(buildingTickers)
			.map((building) => ({ticker: building, expertise: profits.find(p => p.building === building)!.expertise}))
			.sort((a, b) => a.ticker.localeCompare(b.ticker));
	let selectedBuilding = buildingSelect.value;
	let buildingFound = false;
	buildingSelect.innerHTML = '<option value="">(all)</option>';
	for (const building of buildings)
		if (expertiseSelect.value === '' || expertiseSelect.value === building.expertise) {
			const option = document.createElement('option');
			option.value = building.ticker;
			option.textContent = building.ticker;
			if (building.ticker === selectedBuilding) {
				buildingFound = true;
				option.selected = true;
			}
			buildingSelect.appendChild(option);
		}
	if (!buildingFound)
		selectedBuilding = '';

	for (const p of profits) {
		const volumeRatio = p.output_per_day / p.average_traded_7d;
		if (!lowVolume.checked && volumeRatio > 0.05)
			continue;
		if (expertiseSelect.value !== '' && p.expertise !== expertiseSelect.value)
			continue;
		if (selectedBuilding !== '' && p.building !== selectedBuilding)
			continue;
		const tr = document.createElement('tr');
		const profitPerArea = p.profit_per_day / p.area;
		const breakEven = p.profit_per_day > 0 ? p.capex / p.profit_per_day : Infinity;
		tr.innerHTML = `
			<td>${p.outputs.map(o => o.ticker).join(', ')}</td>
			<td>${expertise[p.expertise]}</td>
			<td style="color: ${color(profitPerArea, 0, 300)}">${formatDecimal(profitPerArea)}</td>
			<td><span style="color: ${color(breakEven, 30, 3)}">${formatDecimal(breakEven)}</span>d</td>
			<td style="color: ${color(p.capex, 300_000, 40_000)}">${formatWhole(p.capex)}</td>
			<td style="color: ${color(p.cost_per_day, 40_000, 1_000)}">${formatWhole(p.cost_per_day)}</td>
			<td style="color: ${color(p.logistics_per_area, 2, 0.2)}">${formatDecimal(p.logistics_per_area)}</td>
			<td>
				${formatDecimal(p.output_per_day)}<br>
				<span style="color: ${color(volumeRatio, 0.05, 0.002)}">${formatWhole(p.average_traded_7d)}</span>
			</td>
		`;

		const output = tr.querySelector('td')!;
		output.dataset.tooltip = p.recipe;

		const profitCell = tr.querySelectorAll('td')[2];
		const revenue = p.outputs.reduce((sum, o) => sum + o.amount * o.vwap_7d, 0);
		const inputCost = p.input_costs.reduce((sum, o) => sum + o.amount * o.vwap_7d, 0);
		profitCell.dataset.tooltip = formatMatPrices(p.outputs) + '\n\n' +
			formatMatPrices(p.input_costs) + '\n' +
			'worker consumables: ' + formatWhole(p.worker_consumable_cost_per_day) + '\n\n' +
			`(${formatWhole(revenue)} - ${formatWhole(inputCost)}) × ${formatDecimal(p.runs_per_day)} runs ` +
			`- ${formatWhole(p.worker_consumable_cost_per_day)} = ${formatDecimal(p.profit_per_day)}\n` +
			`${formatDecimal(p.profit_per_day)} / ${formatWhole(p.area)} area = ${formatDecimal(profitPerArea)}`;

		tbody.appendChild(tr);
	}
	document.getElementById('last-updated')!.textContent =
		`last updated: ${lastModified.toLocaleString(undefined, {dateStyle: 'full', timeStyle: 'long', hour12: false})}`;
}

function color(n: number, low: number, high: number): string {
	// scale n from low..high to 0..1 clamped
	const scale = Math.min(Math.max((n - low) / (high - low), 0), 1);
	return `color-mix(in xyz, #0aa ${scale * 100}%, #f80)`;
}

function formatMatPrices(matPrices: MatPrice[]): string {
	return matPrices.map(({ticker, amount, vwap_7d}) =>
		`${ticker}: ${amount} × ${formatDecimal(vwap_7d)} = ${formatWhole(amount * vwap_7d)}`).join('\n');
}

setupPopover();
lowVolume.addEventListener('change', render);
cxSelect.addEventListener('change', render);
expertiseSelect.addEventListener('change', render);
buildingSelect.addEventListener('change', render);
render();

interface Profit {
	outputs: MatPrice[]
	recipe: string
	expertise: keyof typeof expertise
	building: string
	profit_per_day: number
	area: number
	capex: number
	cost_per_day: number
	input_costs: MatPrice[]
	worker_consumable_cost_per_day: number
	runs_per_day: number
	logistics_per_area: number
	output_per_day: number
	average_traded_7d: number
}

interface MatPrice {
	ticker: string
	amount: number
	vwap_7d: number
}

interface Building {
	building_type: 'INFRASTRUCTURE' | 'PLANETARY' | 'PRODUCTION';
	building_ticker: string;
	expertise: keyof typeof expertise;
}
