import {
	Evaluation,
	Exam,
	InteractiveSpeakingExercise,
	SpeakingExam,
	SpeakingExercise,
	UserSolution,
	WritingExam,
	WritingExercise,
} from "@/interfaces/exam";
import axios from "axios";
import {speakingReverseMarking, writingReverseMarking} from "./score";

export const evaluateWritingAnswer = async (
	exercise: WritingExercise,
	task: number,
	solution: UserSolution,
	id: string,
): Promise<UserSolution | undefined> => {
	const response = await axios.post<Evaluation>("/api/evaluate/writing", {
		question: `${exercise.prompt} ${exercise.attachment ? exercise.attachment.description : ""}`.replaceAll("\n", ""),
		answer: solution.solutions[0].solution.trim().replaceAll("\n", " "),
		task,
		id,
	});

	if (response.status === 200) {
		return {
			...solution,
			id,
			score: {
				correct: response.data ? writingReverseMarking[response.data.overall] : 0,
				missing: 0,
				total: 100,
			},
			solutions: [{id: exercise.id, solution: solution.solutions[0].solution, evaluation: response.data}],
			isDisabled: true,
		};
	}

	return undefined;
};

export const evaluateSpeakingAnswer = async (
	exercise: SpeakingExercise | InteractiveSpeakingExercise,
	solution: UserSolution,
	id: string,
	task: number,
): Promise<UserSolution | undefined> => {
	switch (exercise?.type) {
		case "speaking":
			return {...(await evaluateSpeakingExercise(exercise, exercise.id, solution, id, task)), id} as UserSolution;
		case "interactiveSpeaking":
			return {...(await evaluateInteractiveSpeakingExercise(exercise.id, solution, id, task === 3 ? "final" : "initial")), id} as UserSolution;
		default:
			return undefined;
	}
};

export const downloadBlob = async (url: string): Promise<Buffer> => {
	const blobResponse = await axios.get(url, {responseType: "arraybuffer"});
	return Buffer.from(blobResponse.data, "binary");
};

const evaluateSpeakingExercise = async (
	exercise: SpeakingExercise,
	exerciseId: string,
	solution: UserSolution,
	id: string,
	task: number,
): Promise<UserSolution | undefined> => {
	const formData = new FormData();

	const url = solution.solutions[0].solution.trim() as string;
	const audioBlob = await downloadBlob(url);
	const audioFile = new File([audioBlob], "audio.wav", {type: "audio/wav"});

	if (url && !url.startsWith("blob")) await axios.post("/api/storage/delete", {path: url});

	formData.append("audio", audioFile, "audio.wav");

	const evaluationQuestion =
		`${exercise.text.replaceAll("\n", "")}` + (exercise.prompts.length > 0 ? `You should talk about: ${exercise.prompts.join(", ")}` : "");
	formData.append("question", evaluationQuestion);
	formData.append("id", id);
	formData.append("task", task.toString());

	const config = {
		headers: {
			"Content-Type": "audio/wav",
		},
	};

	const response = await axios.post("/api/evaluate/speaking", formData, config);

	if (response.status === 200) {
		return {
			...solution,
			id,
			score: {
				correct: 0,
				missing: 0,
				total: 100,
			},
			solutions: [{id: exerciseId, solution: response.data ? response.data.fullPath : null, evaluation: response.data}],
			isDisabled: true,
		};
	}

	return undefined;
};

const evaluateInteractiveSpeakingExercise = async (
	exerciseId: string,
	solution: UserSolution,
	id: string,
	variant?: "initial" | "final",
): Promise<UserSolution | undefined> => {
	const promiseParts = solution.solutions.map(async (x: {prompt: string; blob: string}) => {
		const blob = await downloadBlob(x.blob);
		if (!x.blob.startsWith("blob")) await axios.post("/api/storage/delete", {path: x.blob});

		return {
			question: x.prompt,
			answer: blob,
		};
	});
	const body = await Promise.all(promiseParts);

	const formData = new FormData();
	body.forEach(({question, answer}) => {
		const seed = Math.random().toString().replace("0.", "");

		const audioFile = new File([answer], `${seed}.wav`, {type: "audio/wav"});

		formData.append(`question_${seed}`, question);
		formData.append(`answer_${seed}`, audioFile, `${seed}.wav`);
	});
	formData.append("id", id);
	formData.append("variant", variant || "final");

	const config = {
		headers: {
			"Content-Type": "audio/mp3",
		},
	};

	const response = await axios.post("/api/evaluate/interactiveSpeaking", formData, config);

	if (response.status === 200) {
		return {
			...solution,
			id,
			score: {
				correct: 0,
				missing: 0,
				total: 100,
			},
			module: "speaking",
			solutions: [{id: exerciseId, solution: response.data ? response.data.answer : null, evaluation: response.data}],
			isDisabled: true,
		};
	}

	return undefined;
};
