import { Schema as S } from "@effect/schema";
import { Login as LoginApi } from "common/api";
import { Effect, Fiber, Option as O, pipe } from "effect";
import { useLocation } from "preact-iso";
import { useId, useMemo, useRef } from "preact/hooks";
import { useStore } from "../store";
import * as style from "./Login.css";

export const Login = () => {

	const { route } = useLocation();

	const loginUsername = useStore(state => state.loginUsername);
	const loginPassword = useStore(state => state.loginPassword);

	const setLoginUsername = useStore(state => state.setLoginUsername);
	const setLoginPassword = useStore(state => state.setLoginPassword);

	const setUser = useStore(state => state.setUser);

	const usernameId = useId();
	const passwordId = useId();

	const requestFiber = useRef<Fiber.RuntimeFiber<void> | null>(null);
	const requestEffect = useMemo(() => Effect.gen(function* () {
		const requestData = LoginApi.props.request.schema.make({ username: loginUsername, password: loginPassword });

		const requestJson = yield* pipe(
			requestData,
			S.encode(LoginApi.props.request.schema),
			Effect.map(JSON.stringify),
			Effect.orDie,
		);

		const res = yield* Effect.promise((signal) => fetch("http://localhost:3000/login", {
			method: "POST",
			body: requestJson,
			headers: { "Content-Type": "application/json" },
			signal,
			credentials: "include",
		}));

		if (!res.ok) {
			yield* Effect.die(new Error("Response was not ok"));
		}

		const responseData = yield* pipe(
			Effect.promise(() => res.json()),
			Effect.flatMap(S.decodeUnknown(LoginApi.props.response[200].schema)),
			Effect.orDie,
		);

		setLoginUsername("");
		setLoginPassword("");
		setUser(O.some(responseData));

		route("/");
	}), [loginUsername, loginPassword]);

	const onSubmit = (e: SubmitEvent) => {
		e.preventDefault();

		if (requestFiber.current !== null) {
			Effect.runFork(Fiber.interrupt(requestFiber.current), { immediate: true });
		}

		requestFiber.current = Effect.runFork(requestEffect);
	};

	return (
		<div class={style.container}>
			<form class={style.box} onSubmit={onSubmit}>
				<header class={style.header}>Repozytorium muzyczne</header>
				<label for={usernameId}>Nazwa użytkownika</label>
				<input
					id={usernameId}
					class={style.input}
					type="text"
					value={loginUsername}
					autofocus
					required
					onInput={(e) => setLoginUsername(e.currentTarget.value)}
				/>
				<label for={passwordId}>Hasło</label>
				<input
					id={passwordId}
					class={style.input}
					type="password"
					value={loginPassword}
					required
					onInput={(e) => setLoginPassword(e.currentTarget.value)}
				/>
				<button class={style.submit} type="submit">Zaloguj się</button>
			</form>
		</div>
	);
};
