import fs from 'fs';
import path from 'path';
import { LoggingService } from './logService';
import Config from '#config';

const logger = new LoggingService();

interface DeleteFileOptions {
	/** The relative path stored in database (e.g., /images/file-123.jpg) */
	filePath: string;
	/** Compressed file paths from compress_info if available */
	compressInfo?: Record<string, string> | null;
}

/**
 * Delete a physical file and its compressed variants from storage
 * @param options - Delete file options containing file path and compress info
 * @returns Promise<boolean> - True if all deletions successful
 */
export async function deleteFile(options: DeleteFileOptions): Promise<boolean> {
	const { filePath, compressInfo } = options;
	const uploadPath = Config.uploads.path;
	const results: boolean[] = [];

	// Delete main file
	const normalizedMain = normalizeFilePath(filePath);
	const mainFilePath = path.resolve(uploadPath, normalizedMain);
	if (!mainFilePath.startsWith(path.resolve(uploadPath))) {
		throw new Error(`Path traversal detected for: ${filePath}`);
	}
	results.push(await deleteFileIfExists(mainFilePath));

	// Delete compressed variants if they exist
	if (compressInfo && typeof compressInfo === 'object') {
		for (const [, compressedPath] of Object.entries(compressInfo)) {
			if (compressedPath) {
				const fullCompressedPath = path.resolve(uploadPath, compressedPath.replace(/^\//, ''));
				if (!fullCompressedPath.startsWith(path.resolve(uploadPath))) {
					throw new Error(`Path traversal detected for compressed variant: ${compressedPath}`);
				}
				results.push(await deleteFileIfExists(fullCompressedPath));
			}
		}
	}

	return results.every((result) => result);
}
function normalizeFilePath(input: string): string {
	return input.replace(/^\/api\/storage\/uploads\/?/, '').replace(/^\//, '');
}

/**
 * Delete a file if it exists
 * @param filePath - Absolute path to the file
 * @returns Promise<boolean> - True if file was deleted or didn't exist
 */
async function deleteFileIfExists(filePath: string): Promise<boolean> {
	try {
		// P2-3: avoid blocking existsSync — attempt unlink and treat ENOENT as success
		await fs.promises.unlink(filePath);
		return true;
	} catch (error: any) {
		if (error.code === 'ENOENT') return true; // idempotent
		await logger.logErrorAsync('deleteFileIfExists', error as Error, null);
		return false;
	}
}

/**
 * Delete multiple files and their compressed variants
 * @param files - Array of file options to delete
 * @returns Promise<{ success: boolean; deleted: number; failed: number }>
 */
export async function deleteFiles(
	files: DeleteFileOptions[],
): Promise<{ success: boolean; deleted: number; failed: number }> {
	let deleted = 0;
	let failed = 0;

	for (const file of files) {
		const result = await deleteFile(file);
		if (result) {
			deleted++;
		} else {
			failed++;
		}
	}

	return {
		success: failed === 0,
		deleted,
		failed,
	};
}

export default deleteFile;
