import { get } from "svelte/store";
import {
	createUserPayloadModel,
	getDefaultPaginatedUserModel,
	getDefaultUsersCursor,
	updateUserInfoInputModel,
	type PaginatedUserModel,
	type UsersCursorModel,
} from "../data/entities";
import { trpcApiStore } from "$lib/stores/api";
import type { Result } from "@pkg/result";
import { toast } from "svelte-sonner";
import { encodeCursor } from "$lib/core/string.utils";
import { users } from "../data/store";
import { userInfo } from "$lib/stores/session.info";
import { trpcRaw } from "$lib/trpc/trpc";

export class UserViewModel {
	userInfo = $state<PaginatedUserModel>(getDefaultPaginatedUserModel());
	discountPercent = $state(0);
	banned = $state(false);
	fetching = $state(false);
	query = $state("");

	creatingUser = $state(false);
	savingUsersInfo = $state(false);

	private getApi() {
		return get(trpcApiStore);
	}

	private _getPayload() {
		return {
			limit: this.userInfo.limit,
			asc: this.userInfo.asc,
			page: this.userInfo.page,
			totalItemCount: this.userInfo.totalItemCount,
			totalPages: this.userInfo.totalPages,
			cursor: this.userInfo.cursor,
		};
	}

	async fetchNextPage() {
		const api = this.getApi();
		if (!this.userInfo || !api) {
			return;
		}
		if (
			this.userInfo.page >= this.userInfo.totalPages &&
			this.userInfo.totalPages > 0
		) {
			console.log("Not fetching next page, at the end");
			return;
		}
		this.fetching = true;

		const res = await api.user.getAgentsPaginatedInfo.query({
			info: this._getPayload(),
			fetchNext: true,
		});
		console.log(res);
		this.fetching = false;
		this.setUserInfoStateInfo(res as Result<PaginatedUserModel>);
	}

	async fetchPrevPage() {
		const api = this.getApi();
		if (!this.userInfo || !api) {
			return;
		}
		if (this.userInfo.page <= 1 || this.userInfo.totalPages <= 1) {
			console.log("Not fetching prev page, at the start");
			return;
		}
		this.fetching = true;
		const res = await api.user.getAgentsPaginatedInfo.query({
			info: this._getPayload(),
			fetchNext: false,
		});
		this.fetching = false;
		this.setUserInfoStateInfo(res as Result<PaginatedUserModel>);
	}

	private setUserInfoStateInfo(res: Result<PaginatedUserModel>) {
		if (res.error) {
			return toast.error(res.error.message, {
				description: res.error.userHint,
			});
		}
		if (!res.data) {
			this.resetUserInfo();
			return;
		}
		users.set(res.data.data);
		this.userInfo = {
			...res.data,
			data: res.data.data.map((item) => {
				return {
					...item,
					createdAt: new Date(item.createdAt),
					updatedAt: new Date(item.updatedAt),
				};
			}),
		};
	}

	async searchUsers() {
		if (!this.userInfo) {
			return;
		}
		this.resetUserInfo();
		await this.fetchNextPage();
	}

	resetUserInfo() {
		this.userInfo = {
			data: [],
			cursor: encodeCursor<UsersCursorModel>({
				...getDefaultUsersCursor(),
				query: this.query,
			}),
			limit: this.userInfo.limit,
			asc: this.userInfo.asc,
			totalItemCount: 0,
			totalPages: 0,
			page: 0,
		};
	}

	// INFO: ----- Mutation methods -----

	async onCreateUserFormSubmit(event: Event) {
		event.preventDefault();
		const _payload = Object.fromEntries(
			new FormData(event.target as HTMLFormElement),
		);
		const parsed = createUserPayloadModel.safeParse({
			email: get(userInfo).email,
			discountPercent: this.discountPercent,
			..._payload,
		});
		if (!parsed.success) {
			const _err = parsed.error.errors[0];
			const msg = `${_err.path[0]} ${_err.message}`;
			toast.error(msg ?? "Please fill in all the required fields");
			return false;
		}
		this.creatingUser = true;

		const api = trpcRaw();
		const { data, error } = await api.user.createUser.mutate(parsed.data);

		this.creatingUser = false;
		if (error || !data) {
			toast.error(
				error?.message ??
					"An error occurred while creating agent, please try again later",
				{ description: error?.userHint },
			);
			return false;
		}
		toast.success("Agent has been created successfully");
		this.resetUserInfo();
		await this.fetchNextPage();
		return true;
	}

	async onUserInfoUpdateFormSubmit(event: Event) {
		event.preventDefault();
		const _payload = Object.fromEntries(
			new FormData(event.target as HTMLFormElement),
		);
		const parsed = updateUserInfoInputModel.safeParse({
			username: get(userInfo).username,
			..._payload,
			discountPercent: this.discountPercent,
			banned:
				_payload.banned === "on" ||
				_payload.banned === "true" ||
				!!_payload.banned,
		});
		if (!parsed.success) {
			const _err = parsed.error.errors[0];
			const msg = `${_err.path[0]} ${_err.message}`;
			toast.error(msg ?? "Please fill in all the required fields");
			return false;
		}
		const data = parsed.data;
		this.savingUsersInfo = true;
		console.log(data);
		const { error } = await trpcRaw().user.updateUserInfo.mutate({
			email: data.email,
			username: data.username,
			banned: data.banned,
			discountPercent: data.discountPercent,
		});
		this.savingUsersInfo = false;
		if (error) {
			return toast.error(
				error.message ??
					"An error occurred while saving info, please try again later",
			);
		}
		toast.success("Changes have been saved");
	}
}

export const userVM = new UserViewModel();
