import MainControl from "@/Common/MainControl/MainControl";
import CSMessage from "@/Common/Message/CSMessage";
import { CoroutineV2 } from "@/Engine/CatanEngine/CoroutineV2/CoroutineV2";
import { INetResponse } from "@/Engine/CatanEngine/NetManagerV2/Core/INetResponse";
import { NetConnector } from "@/Engine/CatanEngine/NetManagerV2/NetConnector";
import { NetManagerSD } from "@/Engine/CatanEngine/NetManagerV2/NetManagerSD";
import CSSettingsSDV3 from "@/FormTableSD/CSSettingsSDV3";
import { SlotsetTableRow } from "@/FormTableSD/Tables/SlotsetTable";
import A from "@/components/CustomA";
import { useGameItems } from "@/context/GameItemsContext";
import { SDAccountLoginRequest } from "@/define/Request/AccountRequest";
import { SlotInRequest } from "@/define/Request/SlotRequest";
import GameManager from "@/modules/GameManager";
import { Button, Checkbox, Dropdown, Flex, Input, MenuProps } from "antd";
import { CheckboxChangeEvent } from "antd/es/checkbox";
import dayjs from "dayjs";
import { ChangeEvent, useEffect, useState } from "react";

const SDGame = (props: ISDGame) => {
	const { gameUrl, onClickSlotOut } = props;
	const { player, setPlayer } = useGameItems();
	const { gameData } = useGameItems();
	const { m: money } = player;
	const { nowSlotId } = gameData;
	const [isOK, setIsOK] = useState<boolean>(false);
	const [isSpin, setIsSpin] = useState<boolean>(false);
	const [items, setItems] = useState<MenuProps["items"]>([]);
	const [bet, setBet] = useState<number>(0);
	const [delay, setDelay] = useState<number>(0.1);
	const [isRatioStop, setIsRatioStop] = useState<boolean>(false);
	const [ratioStop, setRatioStop] = useState<number>(200);
	const [isCountStop, setIsCountStop] = useState<boolean>(false);
	const [countStop, setCountStop] = useState<number>(200);
	const [log, setLog] = useState<string[]>([]);
	let conn: NetConnector = undefined;

	function* onLoad(): IterableIterator<any> {
		const url: URL = new URL(gameUrl);
		const queryParameters: URLSearchParams = new URLSearchParams(url.search);
		const token: string = queryParameters.get("token");
		const slotid: number = +queryParameters.get("slotid");
		const host: string = queryParameters.get("host");
		const port: number = 9005;

		GameManager.SlotData.SlotId = slotid;
		conn = new NetConnector("https://" + host, port);
		conn.OnDataReceived.AddCallback(onNetDataReceived);
		conn.OnDisconnected.AddCallback(onNetDisconnected);
		loadJSON(slotid);
		setSlotClass();
		NetManagerSD.Initialize(conn);
		console.log("[SDsocket] connecting...");
		yield NetManagerSD.ConnectAsync();
		yield* login(token);
		yield* slotIn();
	}

	function* login(token: string): IterableIterator<any> {
		const req = new SDAccountLoginRequest(token);
		yield req.SendAsync(true);
		const resp = req.Result;
		if (!resp.IsValid) {
			CSMessage.NetError(resp.Method, resp.Status, "SD Account Login Fail");
			return;
		}
	}

	function* slotIn(): IterableIterator<any> {
		let req: SlotInRequest = new SlotInRequest(GameManager.SlotData.SlotId);
		yield req.SendAsync(true);
		let resp: INetResponse<JSON> = req.Result;
		if (resp.IsValid) {
			const br: number[] = resp.Data["br"];
			const db: number = resp.Data["db"];
			const betGroup: MenuProps["items"] = [];
			for (let i = 0; i < br.length; i++) {
				betGroup.push({
					key: i,
					label: (
						<A href="#" onClick={() => { setBet(br[i]); GameManager.SlotData.NowBet = br[i]; }}>
							{br[i]}
						</A>
					),
				});
			}
			setItems(betGroup);
			setBet(br[db]);
			GameManager.SlotData.NowBet = br[db];
			setIsOK(true);
		}
	}

	async function loadJSON(slotid: number) {
		let slotset: SlotsetTableRow = CSSettingsSDV3.Slotset[slotid];
		let formName: string[] = slotset.FormName;
		let parallel: Promise<void>[] = [];
		for (let i: number = 0; i < formName.length; i++) {
			await MainControl.DownloadFormSetting(formName[i]);
		}
		// set Form
		await Promise.all(parallel);
	}

	async function setSlotClass() {
		let slot: any;
		const slotGroup: typeof import("../../define/Game/Base/Slot") = await import(/* @vite-ignore */`../../define/Game/Base/Slot`);
		try {
			slot = slotGroup[`Slot${GameManager.SlotData.SlotId}`];
		} catch (error) {
			//
		}
		if (!slot) {
			slot = slotGroup.SlotBase;
		}
		GameManager.SlotData.SlotClass = new slot(GameManager.SlotData.SlotId, AddLog);
	}

	async function OnClickSpin() {
		GameManager.SlotData.IsSpin = true;
		setIsSpin(true);
		CoroutineV2.Single(spin()).Start();
	}

	function OnClickStop() {
		GameManager.SlotData.IsSpin = false;
		setIsSpin(false);
	}

	function* spin(): IterableIterator<any> {
		if (money < GameManager.SlotData.NowBet) {
			noMoney();
			return;
		}
		if (isCountStop) {
			if (GameManager.SlotData.CountStop <= 0) {
				OnClickStop();
				return;
			}
			GameManager.SlotData.CountStop--;
			setCountStop((v) => v - 1);
		}
		yield* GameManager.SlotData.SlotClass.Spin(bet, OnClickStop);
		yield CoroutineV2.WaitTime(delay);
		if (GameManager.SlotData.IsSpin) {
			yield* spin();
		} else {
			GameManager.SlotData.IsSpin = false;
			setIsSpin(false);
		}
	}

	function noMoney(): void {
		GameManager.SlotData.IsSpin = false;
		AddLog(`金額不足: ${money}`);
	}

	function AddLog(s: string) {
		const todayTimeStr: string = dayjs().format("YYYY/MM/DD 00:00:00");
		setLog((v) => {
			if (v.length > 100) {
				v.pop();
			}
			v.unshift(`${todayTimeStr}  ${s}`);
			return v;
		});
	}

	/**RPC回傳.若協定錯誤斷線.原因也會在這裡收到 */
	function onNetDataReceived(resp: INetResponse<any>) {
		// MainControl.DataReceivedEvent.DispatchCallback([MainControl.DataType.ServerData, resp]);
	}

	/**只要連線中斷不管主被動都會走到這裡 */
	function onNetDisconnected() {
		console.warn("[socket] Disconnected");
		conn.OnDataReceived.RemoveAllCallbacks();
		// MainControl.DataReceivedEvent.DispatchCallback([MainControl.DataType.NetDisconnected]);
	}

	useEffect(() => {
		CoroutineV2.Single(onLoad()).Start();
	}, []);

	return (<>
		<div style={siderStyle}>
			{isOK &&
				<Flex gap="small" wrap="wrap">
					<div style={controlStyle}>
						<p>
							押注
							<Dropdown menu={{ items }} placement="bottom">
								<Button>{bet}</Button>
							</Dropdown>
						</p>

						<p>
							延遲
							<Input onInput={(e: ChangeEvent<HTMLInputElement>) => setDelay(+e.target.value)} type="text" value={delay} placeholder={delay.toString()} style={{ width: "10%" }} />
							秒
						</p>

						<p>
							倍率
							<Checkbox onChange={(e: CheckboxChangeEvent) => { setIsRatioStop(e.target.checked); GameManager.SlotData.IsRatioStop = e.target.checked; }} />
							{isRatioStop && <><Input onInput={(e: ChangeEvent<HTMLInputElement>) => { setRatioStop(+e.target.value); GameManager.SlotData.RatioStop = +e.target.value; }} type="text" value={ratioStop} placeholder={ratioStop.toString()} style={{ width: "10%" }} />倍</>}
						</p>

						<p>
							轉數
							<Checkbox onChange={(e: CheckboxChangeEvent) => { setIsCountStop(e.target.checked); GameManager.SlotData.IsCountStop = e.target.checked; }} />
							{isCountStop && <><Input onInput={(e: ChangeEvent<HTMLInputElement>) => { setCountStop(+e.target.value); GameManager.SlotData.CountStop = +e.target.value; }} type="text" value={countStop} placeholder={countStop.toString()} style={{ width: "10%" }} />轉</>}
						</p>

						<p>
							{isSpin
								? <Button type="primary" onClick={OnClickStop} style={{ width: "20%" }}>Stop</Button>
								: <Button type="primary" onClick={OnClickSpin} style={{ width: "20%" }}>Spin</Button>
							}
						</p>
					</div>
					<div style={{ height: "90vh", position: "relative", top: "0%", overflowY: "scroll" }}>
						{log.map((log: string, index: number) => <p key={index}>{log}</p>)}
					</div>
				</Flex>}
			<Button type="primary" danger onClick={onClickSlotOut} style={{ width: "20%", position: "fixed", bottom: "1%" }}>離開機台</Button>
		</div>
	</>);
};

export default SDGame;

interface ISDGame {
	gameUrl: string;
	onClickSlotOut: () => void;
}

const siderStyle: React.CSSProperties = {
	fontSize: "1rem",
	color: "#000000",
	display: "flex",
	textAlign: "left",
	flexDirection: "column",
	justifyContent: "center",
	width: "100%"
};

const controlStyle: React.CSSProperties = {
	fontSize: "1rem",
	display: "flex",
	textAlign: "left",
	flexDirection: "column",
	justifyContent: "center",
	lineHeight: "30px",
	width: "30%"
};