import { AufnahmeClient, ObjektClient, VerbrauchsausweisGewerbeClient } from "#components/Ausweis/types.js";
import { getKlimafaktoren } from "#lib/Klimafaktoren.js";
import { getHeizwertfaktor } from "#lib/server/Heizwertfaktor.js";
import moment from "moment";
import bauwerkskatalog from "./bauwerkskatalog.json" assert { type: "json" }

function vergleichsWertNichtWohngebaeude(ausweis: VerbrauchsausweisGewerbeClient, aufnahme: AufnahmeClient) {
	let tekWerte = new Array(8).fill(0);

	if (aufnahme.gebaeudetyp && aufnahme.gebaeudetyp in bauwerkskatalog){
		tekWerte = bauwerkskatalog[aufnahme.gebaeudetyp as keyof typeof bauwerkskatalog];
	}

	if (!tekWerte) {
		return [0,0];
	}

	let faktorWarmwasser = 1;
	if (ausweis.stromverbrauch_enthaelt_warmwasser) {
		faktorWarmwasser = 0.9;
	}

	let faktorHeizung = 0;
	if (aufnahme.nutzflaeche && aufnahme.nutzflaeche <= 500) {
		faktorHeizung = 1.46;
	} else if (aufnahme.nutzflaeche && aufnahme.nutzflaeche > 500 && aufnahme.nutzflaeche <= 50000) {
		faktorHeizung = 4.53 * (aufnahme.nutzflaeche ** -0.215) + 0.27;
	} else {
		faktorHeizung = 0.71;
	}

	let tekHeizung = tekWerte[0] * faktorHeizung;
	let tekWarmwasser = tekWerte[1] * faktorWarmwasser;
	let tekLueftung = ausweis.stromverbrauch_enthaelt_lueftung ? tekWerte[2] : 0;

	let tekEingebauteBeleuchtung = ausweis.stromverbrauch_enthaelt_beleuchtung ? tekWerte[3] : 0;
	let tekKaelte = ausweis.stromverbrauch_enthaelt_kuehlung ? tekWerte[4] : 0;

	let tekHilfsenergieKuehlung = ausweis.stromverbrauch_enthaelt_kuehlung ? tekWerte[5] : 0;
	let tekBeEntfeuchtung = ausweis.stromverbrauch_enthaelt_kuehlung ? tekWerte[6] : 0;

	// TODO: let tekAufzug = ausweis.nwaufzug ? 2 : 0;
	let tekAufzug = 0;

	let tekSonstiges = (ausweis.stromverbrauch_enthaelt_sonstige != null && ausweis.stromverbrauch_enthaelt_sonstige.length > 0) ? tekWerte[7] : 0;
	
	let vergleichsWertWaerme = tekHeizung + tekKaelte + tekBeEntfeuchtung;
	let vergleichsWertStrom = tekWarmwasser + tekLueftung + tekEingebauteBeleuchtung + tekHilfsenergieKuehlung + tekAufzug + tekSonstiges;

	return [vergleichsWertWaerme, vergleichsWertStrom];
}

/**
 * Gibt einen array bestehend aus 
 * 	[0]: Endenergieverbrauch
 * 	[1]: Primärenergiebedarf
 * zurück.
 * 
 * @param Ausweis ausweis Ein Ausweis dessen Energiebedarf berechnet werden soll
 * @return VerbrauchsausweisGewerbeCalculationResult
 */
export async function endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis: VerbrauchsausweisGewerbeClient, aufnahme: AufnahmeClient, objekt: ObjektClient) {
		if (!aufnahme || !objekt || !ausweis) {
			return null;
		}

		const nutzflaeche = aufnahme.nutzflaeche || 0;
	
		let startdatum = moment(ausweis.startdatum);
	
		let klimafaktoren: Awaited<ReturnType<typeof getKlimafaktoren>> = [{
			month: startdatum.month(),
			year: startdatum.year(),
			klimafaktor: 1
		},
		{
			month: startdatum.month(),
			year: startdatum.year() + 1,
			klimafaktor: 1
		},
		{
			month: startdatum.month(),
			year: startdatum.year() + 2,
			klimafaktor: 1
		}];
	
		try {
			const response = await getKlimafaktoren(ausweis.startdatum, objekt.plz)
			
			if (response) {
				klimafaktoren = response
			}
		} catch (e) {
			// TODO: Entweder setzen wir hier mit falschen Klimafaktoren fort, oder wir geben null zurück.
			// Im Moment setzen wir einfach fort, aber das ist nicht unbedingt die beste Lösung.
			// return null
		}

	// Endenergieverbrauch
	// Um den EEV auszurechnen, müssen die Verbräuche zu kWh konvertiert werden.
	let brennstoff_1 = { coe: 0, energietraeger: "", einheit: "", umrechnungsfaktor: 0, primaerenergiefaktor: 0 }, brennstoff_2 = { coe: 0, energietraeger: "", einheit: "", umrechnungsfaktor: 0, primaerenergiefaktor: 0 };
	if (aufnahme.brennstoff_1 && ausweis.einheit_1) {
		brennstoff_1 = getHeizwertfaktor(aufnahme.brennstoff_1, ausweis.einheit_1);
	}
	

	if (aufnahme.brennstoff_2 && ausweis.einheit_2) {
		brennstoff_2 = getHeizwertfaktor(aufnahme.brennstoff_2, ausweis.einheit_2);
	}

	let energieVerbrauchGesamt_1 = ((ausweis.verbrauch_1 || 0) + (ausweis.verbrauch_2 || 0) + (ausweis.verbrauch_3 || 0)) * brennstoff_1?.umrechnungsfaktor;
	let energieVerbrauchGesamt_2 = ((ausweis.verbrauch_4 || 0) + (ausweis.verbrauch_5 || 0) + (ausweis.verbrauch_6 || 0)) * brennstoff_2?.umrechnungsfaktor;

	let energieVerbrauchWarmwasser_1 = 0;
	let energieVerbrauchWarmwasser_2 = 0;

	if (ausweis.warmwasser_enthalten && ausweis.anteil_warmwasser_1 != 0) {

			// Wenn Warmwasser enthalten und Anteil bekannt
			energieVerbrauchWarmwasser_1 = energieVerbrauchGesamt_1 * ((ausweis.anteil_warmwasser_1 || 0) / 100);
			energieVerbrauchWarmwasser_2 = energieVerbrauchGesamt_2 * ((ausweis.anteil_warmwasser_2 || 0) / 100);
	
	} else if (ausweis.warmwasser_enthalten && ausweis.anteil_warmwasser_1 == 0){
		if (aufnahme.gebaeudetyp == "Krankenhäuser (ohne Forschung und Lehre)" || aufnahme.gebaeudetyp == "Krankenhäuser (ohne Forschung und Lehre) & teilstationäre Versorgung" || aufnahme.gebaeudetyp == "Schwimmhallen") {
			energieVerbrauchWarmwasser_1 = energieVerbrauchGesamt_1 * 0.5;
			energieVerbrauchWarmwasser_2 = energieVerbrauchGesamt_2 * ((ausweis.anteil_warmwasser_2 || 0) / 100);
	
		} else {
			energieVerbrauchWarmwasser_1 = energieVerbrauchGesamt_1 * 0.05;
			energieVerbrauchWarmwasser_2 = energieVerbrauchGesamt_2 * ((ausweis.anteil_warmwasser_2 || 0) / 100);
	
		}
	} else
	{
		energieVerbrauchWarmwasser_1 = 0;
		energieVerbrauchWarmwasser_2 = 0;
	}

	let kuehlungsZuschlag_1: number = 0, kuehlungsZuschlag_2: number = 0;
	if (aufnahme.kuehlung) {
		kuehlungsZuschlag_1 = energieVerbrauchGesamt_1 * ((ausweis.anteil_kuehlung_1 || 0) / 100);
		kuehlungsZuschlag_2 = energieVerbrauchGesamt_2 * ((ausweis.anteil_kuehlung_2 || 0) / 100);
	}

	// Leerstand wird in Prozent angegeben, muss hier aber in eine Zahl zwischen 0 und 1 umgerechnet werden.
	let leerstand = (aufnahme.leerstand || 0) / 100;

	let energieVerbrauchHeizung_1 = energieVerbrauchGesamt_1 - energieVerbrauchWarmwasser_1 - kuehlungsZuschlag_1;
	let energieVerbrauchHeizung_2 = energieVerbrauchGesamt_2 - energieVerbrauchWarmwasser_2 - kuehlungsZuschlag_2;

	let durchschnittsKlimafaktor = klimafaktoren.reduce((acc, c) => acc + c.klimafaktor, 0) / klimafaktoren.length;

	let energieVerbrauchHeizungBereinigt_1 = energieVerbrauchHeizung_1 * durchschnittsKlimafaktor;
	let energieVerbrauchHeizungBereinigt_2 = energieVerbrauchHeizung_2 * durchschnittsKlimafaktor;

	let durchschnittsEnergieVerbrauchHeizungBereingt = (energieVerbrauchHeizungBereinigt_1 + energieVerbrauchHeizungBereinigt_2) / (3 * nutzflaeche);

	let faktorDurchschnittsEnergieVerbrauchHeizungBereinigt = -0.0028 * durchschnittsEnergieVerbrauchHeizungBereingt + 0.9147;

	if (faktorDurchschnittsEnergieVerbrauchHeizungBereinigt <= 0.25) {
		faktorDurchschnittsEnergieVerbrauchHeizungBereinigt = 0.25;
	} else if (faktorDurchschnittsEnergieVerbrauchHeizungBereinigt >= 1.0) {
		faktorDurchschnittsEnergieVerbrauchHeizungBereinigt = 1.0;
	}

	let leerstandsZuschlagHeizung = faktorDurchschnittsEnergieVerbrauchHeizungBereinigt * leerstand * (energieVerbrauchHeizungBereinigt_1 + energieVerbrauchHeizungBereinigt_2);
	let leerstandsZuschlagWarmwasser = leerstand * (energieVerbrauchWarmwasser_1 + energieVerbrauchWarmwasser_2);
	let leerstandsZuschlagKuehlung = leerstand * (kuehlungsZuschlag_1 + kuehlungsZuschlag_2);


	let endEnergieVerbrauch_1 = (energieVerbrauchHeizungBereinigt_1 + energieVerbrauchWarmwasser_1 + kuehlungsZuschlag_1) / (3 * nutzflaeche);
	let endEnergieVerbrauch_2 = (energieVerbrauchHeizungBereinigt_2 + energieVerbrauchWarmwasser_2 + kuehlungsZuschlag_2) / (3 * nutzflaeche);

	let energieVerbrauchStrom = (ausweis.strom_1 || 0) + (ausweis.strom_2 || 0) + (ausweis.strom_3 || 0);
	let leerstandsZuschlagStrom = leerstand * energieVerbrauchStrom;

	let endEnergieVerbrauchStrom = (energieVerbrauchStrom + leerstandsZuschlagStrom) / (3 * nutzflaeche);
	let primaerEnergieVerbrauchStrom = endEnergieVerbrauchStrom * 1.8;

	let co2EmissionenStrom = endEnergieVerbrauchStrom * 0.560;

	let endEnergieVerbrauchLeerstandsZuschlag = (leerstandsZuschlagHeizung + leerstandsZuschlagWarmwasser + leerstandsZuschlagKuehlung) / (3 * nutzflaeche);
	let endEnergieVerbrauchKuehlungsZuschlag_1 = kuehlungsZuschlag_1 / (3 * nutzflaeche);
	let endEnergieVerbrauchKuehlungsZuschlag_2 = kuehlungsZuschlag_2 / (3 * nutzflaeche);

	let primaerEnergieVerbrauch_1 = endEnergieVerbrauch_1 * brennstoff_1.primaerenergiefaktor;
	let primaerEnergieVerbrauch_2 = endEnergieVerbrauch_2 * brennstoff_2.primaerenergiefaktor;

	let primaerEnergieVerbrauchLeerstandsZuschlag = endEnergieVerbrauchLeerstandsZuschlag * brennstoff_1.primaerenergiefaktor;
	let primaerEnergieVerbrauchKuehlungsZuschlag_1 = endEnergieVerbrauchKuehlungsZuschlag_1 * brennstoff_1.primaerenergiefaktor;
	let primaerEnergieVerbrauchKuehlungsZuschlag_2 = endEnergieVerbrauchKuehlungsZuschlag_2 * brennstoff_2.primaerenergiefaktor;

	let co2Emissionen_1 = endEnergieVerbrauch_1 * brennstoff_1.coe;
	let co2Emissionen_2 = endEnergieVerbrauch_2 * brennstoff_2.coe;

	let co2EmissionenLeerstandsZuschlag = endEnergieVerbrauchLeerstandsZuschlag * brennstoff_1.coe;
	let co2EmissionenKuehlungsZuschlag_1 = endEnergieVerbrauchKuehlungsZuschlag_1 * brennstoff_1.coe;
	let co2EmissionenKuehlungsZuschlag_2 = endEnergieVerbrauchKuehlungsZuschlag_2 * brennstoff_2.coe;

	let endEnergieVerbrauchGesamt = endEnergieVerbrauch_1 + endEnergieVerbrauch_2 + endEnergieVerbrauchLeerstandsZuschlag;
	let primaerEnergieVerbrauchGesamt = primaerEnergieVerbrauch_1 + primaerEnergieVerbrauch_2 + primaerEnergieVerbrauchLeerstandsZuschlag + primaerEnergieVerbrauchStrom;
	let co2EmissionenGesamt = co2Emissionen_1 + co2Emissionen_2 + co2EmissionenLeerstandsZuschlag + co2EmissionenStrom;

	let [vergleichsWertWaerme, vergleichsWertStrom] = vergleichsWertNichtWohngebaeude(ausweis, aufnahme);

	// Return all the steps that this function includes for debugging as a json object
	return {
		brennstoff_1,
		brennstoff_2,
		kuehlungsZuschlag_1        : Math.round(kuehlungsZuschlag_1),
		kuehlungsZuschlag_2: Math.round(kuehlungsZuschlag_2),
		durchschnittsKlimafaktor : Math.round(durchschnittsKlimafaktor * 100) / 100,
		Klimafaktor_1            : klimafaktoren[0],
		Klimafaktor_2            : klimafaktoren[1],
		Klimafaktor_3            : klimafaktoren[2],
		anteil_heizung_1: 1 - ((ausweis.anteil_warmwasser_1 || 0) / 100),
		anteil_heizung_2: 1 - ((ausweis.anteil_warmwasser_2 || 0) / 100),
		verbrauch_1_kwh: (ausweis.verbrauch_1 || 0) * brennstoff_1.umrechnungsfaktor,
		verbrauch_2_kwh: (ausweis.verbrauch_2 || 0) * brennstoff_1.umrechnungsfaktor,
		verbrauch_3_kwh: (ausweis.verbrauch_3 || 0) * brennstoff_1.umrechnungsfaktor,
		verbrauch_4_kwh: (ausweis.verbrauch_4 || 0) * brennstoff_2.umrechnungsfaktor,
		verbrauch_5_kwh: (ausweis.verbrauch_5 || 0) * brennstoff_2.umrechnungsfaktor,
		verbrauch_6_kwh: (ausweis.verbrauch_6 || 0) * brennstoff_2.umrechnungsfaktor,
		klimafaktoren            : klimafaktoren,
		nutzflaeche  : Math.round(nutzflaeche),
		leerstand                : leerstand,
		leerstandsZuschlagHeizung: Math.round(leerstandsZuschlagHeizung),
		leerstandsZuschlagWarmwasser: Math.round(leerstandsZuschlagWarmwasser),
		leerstandsZuschlagKuehlung: Math.round(leerstandsZuschlagKuehlung),
		endEnergieVerbrauchLeerstandsZuschlag: Math.round(endEnergieVerbrauchLeerstandsZuschlag),
		endEnergieVerbrauchKuehlungsZuschlag_1: Math.round(endEnergieVerbrauchKuehlungsZuschlag_1),
		endEnergieVerbrauchKuehlungsZuschlag_2: Math.round(endEnergieVerbrauchKuehlungsZuschlag_2),
		coeeffkg                 : co2EmissionenGesamt,
		energieVerbrauchGesamt_1:  Math.round(energieVerbrauchGesamt_1),
		energieVerbrauchGesamt_2:  Math.round(energieVerbrauchGesamt_2),
		energieVerbrauchWarmwasser_1: Math.round(energieVerbrauchWarmwasser_1),
		energieVerbrauchWarmwasser_2: Math.round(energieVerbrauchWarmwasser_2),
		energieVerbrauchHeizung_1: energieVerbrauchHeizung_1,
		energieVerbrauchHeizung_2: energieVerbrauchHeizung_2,
		anteil_warmwasser_1: (ausweis.anteil_warmwasser_1 || 0) / 100,
		anteil_warmwasser_2: (ausweis.anteil_warmwasser_2 || 0) / 100,
		energieVerbrauchHeizungBereinigt_1: Math.round(energieVerbrauchHeizungBereinigt_1),
		energieVerbrauchHeizungBereinigt_2: Math.round(energieVerbrauchHeizungBereinigt_2),
		durchschnittsEnergieVerbrauchHeizungBereingt: Math.round(durchschnittsEnergieVerbrauchHeizungBereingt),
		faktorDurchschnittsEnergieVerbrauchHeizungBereinigt: Math.round(faktorDurchschnittsEnergieVerbrauchHeizungBereinigt * 1000) / 1000,
		endEnergieVerbrauch_1: Math.round(endEnergieVerbrauch_1),
		endEnergieVerbrauch_2: Math.round(endEnergieVerbrauch_2),
		energieVerbrauchStrom: energieVerbrauchStrom,
		leerstandsZuschlagStrom: leerstandsZuschlagStrom,
		endEnergieVerbrauchStrom: Math.round(endEnergieVerbrauchStrom),
		primaerEnergieVerbrauchStrom: Math.round(primaerEnergieVerbrauchStrom),
		primaerEnergieVerbrauch_1: Math.round(primaerEnergieVerbrauch_1),
		primaerEnergieVerbrauch_2: Math.round(primaerEnergieVerbrauch_2),
		primaerEnergieVerbrauchLeerstandsZuschlag: Math.round(primaerEnergieVerbrauchLeerstandsZuschlag),
		primaerEnergieVerbrauchKuehlungsZuschlag_1: Math.round(primaerEnergieVerbrauchKuehlungsZuschlag_1),
		primaerEnergieVerbrauchKuehlungsZuschlag_2: Math.round(primaerEnergieVerbrauchKuehlungsZuschlag_2),
		co2Emissionen_1: co2Emissionen_1,
		co2Emissionen_2: co2Emissionen_2,
		co2EmissionenLeerstandsZuschlag: co2EmissionenLeerstandsZuschlag,
		co2EmissionenKuehlungsZuschlag_1: co2EmissionenKuehlungsZuschlag_1,
		co2EmissionenKuehlungsZuschlag_2: co2EmissionenKuehlungsZuschlag_2,
		co2EmissionenGesamt: Math.round(co2EmissionenGesamt),
		endEnergieVerbrauchGesamt: Math.round(endEnergieVerbrauchGesamt),
		primaerEnergieVerbrauchGesamt: Math.round(primaerEnergieVerbrauchGesamt),
		vergleichsWertWaerme: vergleichsWertWaerme,
		vergleichsWertStrom: vergleichsWertStrom,
	}
}