// #region TranslateCorrectionsApi [C:2] [TYPE Module] [SEMANTICS translate, corrections, bulk-replace, api]
// @BRIEF API client for translation corrections — inline edits, dictionary submission, bulk find-and-replace, CSV download.
// @LAYER API
// @RELATION DEPENDS_ON -> [ApiModule]
// @POST All functions return typed responses or throw normalized TranslateApiError.

import { api } from '$lib/api';
import type { TranslateApiError } from './jobs';

function normalizeTranslateError(error: unknown, defaultMessage: string = 'Translation API error'): TranslateApiError {
	const message =
		(error && typeof (error as Error).message === 'string' && (error as Error).message) ||
		(typeof error === 'string' && error) ||
		defaultMessage;
	return { message, code: 'TRANSLATE_API_ERROR' as const, retryable: true };
}

// #region submitCorrection [C:2] [TYPE Function] [SEMANTICS translate, corrections, submit]
// @BRIEF Submit a single correction for a translation record.
// @PRE payload contains record_id, language_code, and corrected_text.
// @POST Returns correction confirmation.
// @SIDE_EFFECT Updates the translation on the backend.
// @RELATION DEPENDS_ON -> [ApiModule.postApi]
export async function submitCorrection<T = unknown>(payload: Record<string, unknown>): Promise<T> {
	try {
		return await api.postApi<T>('/translate/corrections', payload);
	} catch (error) {
		throw normalizeTranslateError(error, 'Failed to submit correction');
	}
}
// #endregion submitCorrection

// #region submitBulkCorrections [C:2] [TYPE Function] [SEMANTICS translate, corrections, bulk, submit]
// @BRIEF Submit multiple corrections in a single request.
// @PRE payload contains array of correction objects.
// @POST Returns bulk confirmation with per-item results.
// @SIDE_EFFECT Updates multiple translations on the backend.
// @RELATION DEPENDS_ON -> [ApiModule.postApi]
export async function submitBulkCorrections<T = unknown>(payload: Record<string, unknown>): Promise<T> {
	try {
		return await api.postApi<T>('/translate/corrections/bulk', payload);
	} catch (error) {
		throw normalizeTranslateError(error, 'Failed to submit bulk corrections');
	}
}
// #endregion submitBulkCorrections

// #region inlineEditCorrection [C:2] [TYPE Function] [SEMANTICS translate, corrections, inline, edit]
// @BRIEF Apply an inline correction to a specific record+language combination in a run.
// @PRE runId, recordId, languageCode are non-empty strings. data contains corrected values.
// @POST Returns updated record data.
// @SIDE_EFFECT Modifies translation for the specified record+language.
// @RELATION DEPENDS_ON -> [ApiModule.requestApi]
export async function inlineEditCorrection<T = unknown>(runId: string, recordId: string, languageCode: string, data: Record<string, unknown>): Promise<T> {
	try {
		return await api.requestApi<T>(
			`/translate/runs/${runId}/records/${recordId}/languages/${languageCode}`,
			'PUT',
			data
		);
	} catch (error) {
		throw normalizeTranslateError(error, 'Failed to apply inline correction');
	}
}
// #endregion inlineEditCorrection

// #region submitCorrectionToDict [C:2] [TYPE Function] [SEMANTICS translate, corrections, dictionary, submit]
// @BRIEF Submit a correction to be added as a dictionary entry.
// @PRE runId, recordId, languageCode, dictId are non-empty strings.
// @POST Creates a dictionary entry from the correction.
// @SIDE_EFFECT Adds entry to the specified dictionary on the backend.
// @RELATION DEPENDS_ON -> [ApiModule.requestApi]
export async function submitCorrectionToDict<T = unknown>(runId: string, recordId: string, languageCode: string, dictId: string): Promise<T> {
	try {
		return await api.requestApi<T>(
			`/translate/runs/${runId}/records/${recordId}/languages/${languageCode}/submit-to-dict`,
			'POST',
			{ dictionary_id: dictId }
		);
	} catch (error) {
		throw normalizeTranslateError(error, 'Failed to submit correction to dictionary');
	}
}
// #endregion submitCorrectionToDict

// #region bulkFindReplace [C:2] [TYPE Function] [SEMANTICS translate, corrections, bulk, find-replace]
// @BRIEF Perform bulk find-and-replace across a translation run.
// @PRE runId is a non-empty string. data contains find/replace patterns.
// @POST Returns bulk operation results.
// @SIDE_EFFECT Applies find-and-replace to multiple records.
// @RELATION DEPENDS_ON -> [ApiModule.postApi]
export async function bulkFindReplace<T = unknown>(runId: string, data: Record<string, unknown>): Promise<T> {
	try {
		return await api.postApi<T>(`/translate/runs/${runId}/bulk-replace`, data);
	} catch (error) {
		throw normalizeTranslateError(error, 'Failed to perform bulk find-and-replace');
	}
}
// #endregion bulkFindReplace

// #region bulkReplacePreview [C:2] [TYPE Function] [SEMANTICS translate, corrections, bulk, preview]
// @BRIEF Preview bulk find-and-replace operation (dry run, no changes applied).
// @PRE runId is a non-empty string. data contains find/replace patterns.
// @POST Returns preview with affected record count. No changes are persisted.
// @RELATION DEPENDS_ON -> [ApiModule.postApi]
export async function bulkReplacePreview<T = unknown>(runId: string, data: Record<string, unknown>): Promise<T> {
	try {
		return await api.postApi<T>(`/translate/runs/${runId}/bulk-replace`, { ...data, preview: true });
	} catch (error) {
		throw normalizeTranslateError(error, 'Failed to preview bulk find-and-replace');
	}
}
// #endregion bulkReplacePreview

// #region downloadSkippedCsv [C:2] [TYPE Function] [SEMANTICS translate, corrections, csv, download]
// @BRIEF Download a CSV of skipped records for a translation run.
// @PRE runId is a non-empty string.
// @POST Triggers browser download of a CSV file. Returns nothing on success.
// @SIDE_EFFECT Creates a Blob URL and programmatically clicks a download anchor.
// @RELATION DEPENDS_ON -> [ApiModule.fetchApiBlob]
export async function downloadSkippedCsv(runId: string): Promise<void> {
	try {
		const blob = await api.fetchApiBlob(`/translate/runs/${runId}/skipped.csv`);
		const url = URL.createObjectURL(blob);
		const a = document.createElement('a');
		a.href = url;
		a.download = `skipped-${runId.substring(0, 8)}.csv`;
		document.body.appendChild(a);
		a.click();
		document.body.removeChild(a);
		URL.revokeObjectURL(url);
	} catch (error) {
		throw normalizeTranslateError(error, 'Failed to download skipped CSV');
	}
}
// #endregion downloadSkippedCsv

// #region downloadFailedCsv [C:2] [TYPE Function] [SEMANTICS translate, corrections, csv, download]
// @BRIEF Download a CSV of successfully translated but uninserted records for a FAILED run.
// @PRE runId is a non-empty string. The run must have status=FAILED or insert_status=failed.
// @POST Triggers browser download of a CSV file. Returns nothing on success.
// @SIDE_EFFECT Creates a Blob URL and programmatically clicks a download anchor.
// @RATIONALE When INSERT into target DB fails, users need to recover translated data for manual import.
// @RELATION DEPENDS_ON -> [ApiModule.fetchApiBlob]
export async function downloadFailedCsv(runId: string): Promise<void> {
	try {
		const blob = await api.fetchApiBlob(`/translate/runs/${runId}/failed.csv`);
		const url = URL.createObjectURL(blob);
		const a = document.createElement('a');
		a.href = url;
		a.download = `failed-${runId.substring(0, 8)}.csv`;
		document.body.appendChild(a);
		a.click();
		document.body.removeChild(a);
		URL.revokeObjectURL(url);
	} catch (error) {
		throw normalizeTranslateError(error, 'Failed to download failed CSV');
	}
}
// #endregion downloadFailedCsv
// #endregion TranslateCorrectionsApi
