import { GuildScheduledEventEntityType, GuildScheduledEventPrivacyLevel, TextChannel } from "discord.js";
import { CClient, Modul } from "../utils/types";
import { log } from "../utils/utils";
import { RawData, WebSocket } from "ws";

let client: CClient;

const logg = (...cokoli: any[]) => log("[OnePlayTest]: ", ...cokoli);

const token = process.env.OnePlayToken;

let clientId: string | undefined = undefined;
let sessionId: string | undefined = undefined;
let serverId: string | undefined = undefined;

function createOneplayBody(payload: Record<string, any>, customData: string) {

	if (typeof clientId == "undefined" || typeof sessionId == "undefined" || typeof serverId == "undefined") {
		throw new Error("není všechnno nastaveno");
	}

	const vec = {
		"deviceInfo": {
			"deviceType": "web",
			"appVersion": "1.0.18",
			"deviceManufacturer": "Unknown",
			"deviceOs": "Windows"
		},
		"capabilities": {
			"async": "websockets"
		},
		"payload": payload,
		"context": {
			"customData": customData,
			"requestId": crypto.randomUUID(),
			"clientId": clientId,
			"sessionId": sessionId,
			"serverId": serverId
		}
	};

	return JSON.stringify(vec);
}

async function udelejOneplayRquest(cesta: string, body: string) {
	if (!token) {
		throw new Error("token more");
	}

	const res = await fetch(`https://http.cms.jyxo.cz/api/v3/${cesta}`, {
		method: "POST",
		body,
		headers: { Authorization: token }
	}).then(res => res.json())
		.catch(e => { throw new Error(`chyba pri udelejoneplayrequest fetch ${e}`); });

	logg("nejspis uspesna odpoved", res);
}

const sleep = (time: number) => new Promise(res => setTimeout(res, time));

async function executeOrdinaceFlow() {

	// Inicializace
	await udelejOneplayRquest("app.init", createOneplayBody({
		"reason": "start",
		"route": {
			"url": "https://www.oneplay.cz/porad/1-ordinace-v-ruzove-zahrade-2"
		}
	}, `{"requireStartAction":true}`));

	await sleep(500);

	// Navigace na stránku Ordinace
	await udelejOneplayRquest("page.content.display", createOneplayBody({
		contentId: "show.1"
	}, `{"shouldBeInModal":true}`));

	await sleep(500);

	// Otevření 24. řady
	await udelejOneplayRquest("carousel.display", createOneplayBody({
		carouselId: "show:1;tab:65;parent:64;carousel:65",
		criteria: {
			filterCriterias: "season:6947",
			sortOption: "DESC"
		}
	}, `{"blockId":"show:1;tab:65;parent:64;block:65"}`));

}

const handleMessageAndGetNazev = (socket: WebSocket) => new Promise<string | void>((res, rej) => {
	const listener = (m: RawData) => {
		//const mes = m.toString();
		//logg("data:", mes);

		const json = JSON.parse(m.toString());

		logg("celyjson je", json);

		// if (mes.includes("\"schema\":\"Ping\"")) {
		// 	logg("pingec, odpovidam");

		// 	socket.send(`{"schema":"Pong"}`);
		// }

		if (json.result?.schema == "ConnectionInitData") {
			logg("jojo,slysim a jdu na to");
			serverId = json.data.serverId;
			sessionId = json.data.sessionId;
			logg("serverid", serverId, "sessionid", sessionId);
			executeOrdinaceFlow().catch(rej);
		}
		else if (json?.schema == "ApiCall" && json?.command == "carousel.display") {
			logg("máme tady názvy epizod zvolené série");

			const nazev = json?.response?.data?.carousel?.tiles?.[0]?.title;

			//logg(typeof json, typeof json?.response, typeof json?.response?.data, typeof json?.response?.data?.carousel, typeof json?.response?.data?.carousel?.titles);

			if (!nazev) {
				return rej("nazev neexistuje");
			}

			clearTimeout(timeout);
			socket.off("message", listener);
			res(nazev);
		}
	};

	const timeout = setTimeout(() => {
		socket.off("message", listener); // Odstraníme posluchač
		rej(new Error("Časový limit vypršel, jméno nebylo přijato."));
	}, 10000); // Timeout 10 sekund


	socket.on("message", listener);
});

async function ziskatNazev() {
	// Tak tohle stojí fakt za hovno oproti voyu :sjeta:

	clientId = crypto.randomUUID();

	logg("moje Ws id je", clientId);

	let socket: WebSocket | null = null;

	try {
		socket = new WebSocket(`wss://ws.cms.jyxo.cz/websocket/${clientId}`);

		return await handleMessageAndGetNazev(socket);
	} catch (e) {
		logg("nazev ordinace se nepodarilo ziskat", e);
		throw new Error("nazev neni");
	} finally {
		socket?.close();
		logg("zavrel jsem soket");
	}
}

async function naplanovat() {
	const datum = new Date();
	const den = datum.getDay();

	if (!(den == 1 && datum.getHours() < 12))
		datum.setDate(datum.getDate() + ((den == 0 ? 1 : 8) - den));

	datum.setHours(13);
	datum.setMinutes(0);
	datum.setSeconds(0);

	setTimeout(urobit, Number(datum) - Number(new Date()));
}

async function urobit() {
	const guilda = client.guilds.cache.get("555779161067749446");

	if (!guilda) return log(new Error("dobytcarna nenalezena"));

	const kdyToBude = new Date();
	kdyToBude.setHours(20);
	kdyToBude.setSeconds(0);

	const event = await guilda.scheduledEvents.create({
		name: (await ziskatNazev()) || "Vordinačka",
		scheduledStartTime: kdyToBude,
		entityType: GuildScheduledEventEntityType.Voice,
		privacyLevel: GuildScheduledEventPrivacyLevel.GuildOnly,
		channel: "891067481651839037"
	});

	const general = guilda.channels.cache.get("555779161067749448") as TextChannel;

	if (!general) return log(new Error("general nenalezen"));

	general.send(`<@&1123186280843444274> ${event.url}`);

	naplanovat();
}

const exp: Modul = {
	more_komandy: {
		dalsiordinacka: () => `dalsi ordnacka <t:${Math.ceil((Date.now() - 414000000) / 604800000) * 604800 + 414000}:R>`
	},

	on_ready: () => {
		client = module.exports.client;

		if (token) {
			naplanovat();
			//logg("nazev ordinace je:", await ziskatNazev());
		}
	}
};

module.exports = exp;
