"use server";

import {
	sequelize,
	Bucket,
	Auth,
	Post,
	PostTag,
	Tag,
	User,
	dbSync,
} from "@/models";
import { cookies } from "next/headers";
import { Attachment } from "@/models";
import {
    addToExistingBucket,
	addToNewBucketForPost,
	writeFilesToFS,
} from "@/app/lib/actions/entitymanagement/attachment/attachmentActions";
import { Attributes } from "@sequelize/core";
import { RequestCookie } from "next/dist/compiled/@edge-runtime/cookies";
import { APIError, attemptAPIAction } from "@/util/api";

export async function tryCreateAttachment(request: Request) {
	// Make sure the DB is ready
	await dbSync;

	// Prepare data
	const formData = await request.formData();
	const requestData: string | Object | undefined = formData
		.get("data")
		?.valueOf();
	const files: FormDataEntryValue[] = formData.getAll("files");
	const authCkie: RequestCookie | undefined = await cookies().get("auth");

	// Sanity check auth cookie
	if (!authCkie || !authCkie.value)
		throw new APIError({
			status: 500,
			responseText: "missing auth cookie",
		});

	// Get JSON from the Cookie
	const cookieJSON: string = authCkie.value;
	const authObject:Attributes<Auth> = JSON.parse(cookieJSON);

	// Fetch User Auth from thse database
	const auth = await Auth.findOne({
		include: [
			{
				model: User.withScope(["withPerms"]),
				attributes: {
					exclude: ["username", "password", "updatedAt", "createdAt"],
				},
			},
		],
		where: { token: authObject.token },
	});

	// Sanity check the auth and associated user for authorization
	if (!auth || !auth.user)
		throw new APIError({
			status: 401,
			responseText: "Authentication Error",
		});
	if (!auth.user.id)
		throw new APIError({ status: 401, responseText: "Missing user id" });
	if (!auth.user.perms || !auth.user.perms.isAdmin)
		throw new APIError({ status: 401, responseText: `Unauthorized` });
	// Handle incomplete data or other problems
	if (!files)
		throw new APIError({ status: 500, responseText: "Missing file" });
	if (!formData)
		throw new APIError({ status: 500, responseText: "Empty request body" });
	if (!requestData)
		throw new APIError({
			status: 500,
			responseText: "Missing request data",
		});
	if (!(typeof requestData == "string"))
		throw new APIError({
			status: 500,
			responseText: "Malformed request data",
		});

	// Parse JSON
	const data = JSON.parse(requestData);

	// Get or create bucket
	const bucket: Bucket =
		data.postid && !data.bucketid
			? await addToNewBucketForPost(data.postid)
			: await addToExistingBucket(data.bucketid);

	// Write files to bucket and store as attachments in DB
	const writeResult = await writeFilesToFS(bucket.id, files);
	// Handle failure
	if (!writeResult.success)
		throw new APIError({
			status: 500,
			responseText: "Error writing files to Bucket",
		});

	// Write attachments to db
	const attachments = writeResult.filePaths.map(async (fp) => {
		return await Attachment.create(
			{
				bucket_id: bucket.id,
				filename: fp,
			},
			{ include: Attachment.associations.bucket }
		);
	});
	attachments;

	return new Response(
		JSON.stringify({
			bucket: await Bucket.findOne({
				where: { id: bucket.id },
				include: [
					Bucket.associations.posts,
					Bucket.associations.attachments,
				],
			}),
		}),
		{ status: 200 }
	);
}



/**
 * @swagger
 * /api/attachment:
 *   get:
 *     description: Returns all attachments
 *     responses:
 *       200:
 *         description: idk
 */
export async function tryFetchAttachments(request: Request) {
	await Post.sync();

	const foundPosts = await Post.findAll({
		include: [
			{
				association: Post.associations.user,
				attributes: { exclude: ["password", "createdAt", "updatedAt"] },
			},
			{
				association: Post.associations.postTags,
			},
		],
	});

	return new Response(JSON.stringify(foundPosts), { status: 200 });
}

export async function GET(request: Request) {
	return await attemptAPIAction(tryFetchAttachments, request);
}

export async function POST(request: Request) {
	return await attemptAPIAction(tryCreateAttachment, request);
}
