import {cfg} from './config.mjs';
import {frostRisk} from './openweather.mjs';

async function query(c, q, start, end) {
	const url = new URL('/api/v1/query_range', c.DB_HOST);
	url.searchParams.set('query', q);
	url.searchParams.set('step',  '60s');
	if (start) url.searchParams.set('start', start);
	if (end)   url.searchParams.set('end',   end);
	const res  = await fetch(url);
	const json = await res.json();
	return json.data?.result || [];
}

async function queryInstant(c, q) {
	const url = new URL('/api/v1/query', c.DB_HOST);
	url.searchParams.set('query', q);
	const res  = await fetch(url);
	const json = await res.json();
	return json.data?.result || [];
}

function metricToFields(results) {
	const out = {};
	for (const r of results) {
		if(r.metric.__name__.startsWith('system_')) continue;
		const val = r.value?.[1] ?? r.values?.at(-1)?.[1];
		if (val !== undefined) out[r.metric.__name__.replace('weather_', '')] = parseFloat(val);
	}
	return out;
}

export async function queryCurrent() {
	const c       = cfg()
	const results = await queryInstant(c, `{__name__!=""}`)
	const fields  = metricToFields(results)
	const dp      = fields.dew_point ?? null
	return {
		time: new Date(),
		...fields,
		frost_risk: frostRisk(fields.temperature ?? 99, dp ?? 99, fields.humidity ?? 0),
	}
}

export async function queryHourly(start, end) {
	const c      = cfg();
	const s      = Math.floor(start.getTime() / 1000);
	const e      = Math.floor(end.getTime()   / 1000);
	const byTime = {};

	const results = await query(c, `avg_over_time({__name__!=""}[1h])`, s, e);
	results.forEach(r => {
		r.values.forEach(([ts, val]) => {
			if(r.metric.__name__.startsWith('system_')) return;
			const time = new Date(ts * 1000).toISOString().slice(0, 13) + ':00';
			if (!byTime[time]) byTime[time] = {time};
			byTime[time][r.metric.__name__.replace('weather_', '')] = parseFloat(val);
		});
	});
	return Object.values(byTime)
		.sort((a, b) => a.time.localeCompare(b.time))
		.map(r => ({ ...r, time: new Date(r.time) }));
}

export async function queryDaily(start, end) {
	const c      = cfg();
	const s      = Math.floor(start.getTime() / 1000);
	const e      = Math.floor(end.getTime()   / 1000);
	const byTime = {};

	const [means, mins, maxs] = await Promise.all([
		query(c, `avg_over_time({__name__!=""}[1d])`, s, e),
		query(c, `min_over_time({__name__!=""}[1d])`, s, e),
		query(c, `max_over_time({__name__!=""}[1d])`, s, e),
	]);

	means.forEach(r => {
		r.values.forEach(([ts, val]) => {
			if(r.metric.__name__.startsWith('system_')) return;
			const time = new Date(ts * 1000).toISOString().slice(0, 10);
			if (!byTime[time]) byTime[time] = {time};
			byTime[time][r.metric.__name__.replace('weather_', '')] = parseFloat(val);
		});
	});

	mins.forEach(r => {
		if (r.metric.__name__ !== 'temperature') return;
		r.values.forEach(([ts, val]) => {
			const time = new Date(ts * 1000).toISOString().slice(0, 10);
			if (!byTime[time]) byTime[time] = {time};
			byTime[time].env_temp_min_c = parseFloat(val);
		});
	});

	maxs.forEach(r => {
		if (r.metric.__name__ !== 'temperature') return;
		r.values.forEach(([ts, val]) => {
			const time = new Date(ts * 1000).toISOString().slice(0, 10);
			if (!byTime[time]) byTime[time] = {time};
			byTime[time].env_temp_max_c = parseFloat(val);
		});
	});

	return Object.values(byTime)
		.sort((a, b) => a.time.localeCompare(b.time))
		.map(r => ({ ...r, time: new Date(r.time) }));
}

export async function getCoords() {
	const c       = cfg();
	const results = await queryInstant(c, `{__name__=~"latitude|longitude|altitude"}`);
	const fields  = metricToFields(results);

	if (fields.latitude && fields.longitude) {
		return {latitude: fields.latitude, longitude: fields.longitude, altitude: fields.altitude || c.ALTITUDE};
	}
	return {latitude: c.LATITUDE, longitude: c.LONGITUDE, altitude: c.ALTITUDE};
}
