import type { ModuleSensorResponse } from "../../../types/meteo";

export type MeteoSensorSet = {
    temperature?: ModuleSensorResponse;
    humidity?: ModuleSensorResponse;
    windDirection?: ModuleSensorResponse;
    windSpeed?: ModuleSensorResponse;
    radiation?: ModuleSensorResponse;
    rain?: ModuleSensorResponse;
    co2?: ModuleSensorResponse;
};

export function selectMeteoSensors(
    sensors: ModuleSensorResponse[],
): MeteoSensorSet {
    return {
        temperature: firstNumericMatch(sensors, [
            "temperatura exterior",
            "exterior temperature",
            "temperature exterior",
        ]),

        humidity: firstNumericMatch(sensors, [
            "humidade exterior",
            "exterior humidity",
            "humidity exterior",
        ]),

        windDirection: firstNumericMatch(sensors, [
            "direcao vento",
            "direção vento",
            "wind direction",
        ]),

        windSpeed: maxNumericMatch(sensors, [
            "velocidade vento",
            "wind speed",
        ]),

        radiation: maxNumericMatch(sensors, [
            "radiacao",
            "radiação",
            "radiation",
        ]),

        rain: maxNumericMatch(sensors, [
            "chuva",
            "rain",
        ]),

        co2: maxNumericMatch(sensors, [
            "co",
            "co2",
        ]),
    };
}

export function numericSensorValue(
    sensor?: ModuleSensorResponse | null,
): number | null {
    return typeof sensor?.value === "number" && Number.isFinite(sensor.value)
        ? sensor.value
        : null;
}

function firstNumericMatch(
    sensors: ModuleSensorResponse[],
    terms: string[],
): ModuleSensorResponse | undefined {
    return sensors.find(
        (sensor) =>
            matchesAny(sensor, terms) &&
            numericSensorValue(sensor) !== null,
    );
}

function maxNumericMatch(
    sensors: ModuleSensorResponse[],
    terms: string[],
): ModuleSensorResponse | undefined {
    return sensors
        .filter(
            (sensor) =>
                matchesAny(sensor, terms) &&
                numericSensorValue(sensor) !== null,
        )
        .sort(
            (a, b) =>
                Number(b.value) - Number(a.value),
        )[0];
}

function matchesAny(
    sensor: ModuleSensorResponse,
    terms: string[],
): boolean {
    const haystack = normalizeText(`${sensor.key} ${sensor.name}`);

    return terms.some((term) =>
        haystack.includes(normalizeText(term)),
    );
}

function normalizeText(value: string): string {
    return value
        .toLowerCase()
        .normalize("NFD")
        .replace(/\p{Diacritic}/gu, "");
}