"use client";
import { API_URL } from "@/lib/constants";
import { getCookie } from "cookies-next";
import useSWR, { SWRConfiguration } from "swr";
import useSWRMutation, { type SWRMutationConfiguration } from "swr/mutation";

export interface ApiResponse<T> {
	status: "Error" | "Success";
	message: string;
	data?: T;
}

export async function request<T>(
	endpoint: string,
	options: {
		method?: "GET" | "POST" | "PATCH" | "DELETE";
		body?: any;
		requiresAuth?: boolean;
		csrfToken?: boolean;
	} = {},
): Promise<ApiResponse<T>> {
	const { method = "GET", body, requiresAuth = true } = options;
	const headers: Record<string, string> = {
		"Content-Type": "application/json",
	};

	if (options.csrfToken) {
		const res: ApiResponse<{ csrf: string }> = await (
			await fetch(`${API_URL}/csrf-token`)
		).json();
		if (res.data) headers["X-CSRF-Token"] = res.data.csrf;
	}

	if (requiresAuth) {
		const authToken = getCookie("auth_token");
		if (!authToken) {
			throw new Error("User is not authenticated");
		}
		headers.Authorization = `Bearer ${authToken}`;
	}

	const response = await fetch(`${API_URL}${endpoint}`, {
		method,
		headers,
		body: body ? JSON.stringify(body) : undefined,
		credentials: options.csrfToken ? "include" : "omit",
	});

	const apiResponse: ApiResponse<T> = await response.json();

	if (apiResponse.status === "Error") {
		throw new Error(apiResponse.message || "An unexpected error occurred");
	}

	return apiResponse;
}

async function fetcher<T>(
	url: string,
	requiresAuth: boolean = true,
	csrfToken?: boolean,
): Promise<ApiResponse<T>> {
	return request(url, { requiresAuth, csrfToken });
}

async function mutationHandler<T, A>(
	url: string,
	{
		arg,
		method,
		requiresAuth,
		csrfToken,
	}: {
		arg: A;
		method: "GET" | "POST" | "PATCH" | "DELETE";
		requiresAuth: boolean;
		csrfToken?: boolean;
	},
): Promise<ApiResponse<T>> {
	return request(url, { method, body: arg, requiresAuth, csrfToken });
}

export function useApi<T>(
	endpoint: string,
	config?: SWRConfiguration,
	requiresAuth: boolean = true,
	csrfToken?: boolean,
) {
	const swr = useSWR<ApiResponse<T>>(
		endpoint,
		() => fetcher(endpoint, requiresAuth, csrfToken),
		config,
	);

	return {
		...swr,
		data: swr.data?.data,
		isLoading: swr.isLoading || swr.isValidating,
		success: swr.data?.status === "Success",
	};
}

export default function useApiMutation<T, A>(
	endpoint: string,
	config?: SWRMutationConfiguration<ApiResponse<T>, Error, string, A>,
	method: "GET" | "POST" | "PATCH" | "DELETE" = "GET",
	requiresAuth: boolean = false,
	csrfToken?: boolean,
) {
	const mutation = useSWRMutation<ApiResponse<T>, Error, string, A>(
		endpoint,
		(url, { arg }) =>
			mutationHandler(url, { arg, method, requiresAuth, csrfToken }),
		config,
	);
	return {
		...mutation,
		trigger: mutation.trigger as (
			arg: A,
		) => Promise<ApiResponse<T> | undefined>,
		data: mutation.data?.data,
		isSuccess: mutation.data?.status === "Success",
	};
}
