import { Application } from 'express';
import { Resource } from 'express-automatic-routes';
import { Op } from 'sequelize';
import { File } from '#models/File';
import { Req, Res } from '#interfaces/IApi';
import verify from '#middlewares/auth';
import { getStorageAdapter } from '#services/storage/adapters/StorageFactory';
import { Errors, GenericError } from '#interfaces/error';
import { sendSuccess } from '#utils/responseUtils';
import Config from '#config';

const MAX_BATCH = 100;

export default (_express: Application) => {
	return <Resource>{
		post: {
			middleware: [verify],
			handler: async (req: Req, res: Res) => {
				try {
					const { file_ids, mode } = req.body as { file_ids?: unknown; mode?: unknown };

					if (!Array.isArray(file_ids) || file_ids.length === 0) {
						throw Errors.validation([
							{
								field: 'file_ids',
								code: 'MISSING_FILE_FIELDS',
								message: { vi: 'file_ids phải là mảng không rỗng', en: 'file_ids must be a non-empty array' },
							},
						]);
					}

					if (file_ids.length > MAX_BATCH) {
						throw Errors.validation([
							{
								field: 'file_ids',
								code: 'VALUE_TOO_LONG',
								message: {
									vi: `Tối đa ${MAX_BATCH} file mỗi request`,
									en: `Maximum ${MAX_BATCH} file IDs per request`,
								},
							},
						]);
					}

					// Get mode from request body (default: view for preview)
					const modeValue = mode === 'download' ? 'download' : 'view';
					const disposition = modeValue === 'download' ? 'attachment' : 'inline';

					const storageAdapter = getStorageAdapter();

					// PERF-01: Single batch query instead of N+1 individual queries
					const foundFiles = await File.findAll({
						where: { id: { [Op.in]: file_ids as string[] } },
					});
					const fileMap = new Map(foundFiles.map((f) => [f.id, f]));

					const results = await Promise.all(
						(file_ids as string[]).map(async (file_id) => {
							try {
								// Use fileMap from batch query
								const file = fileMap.get(file_id);

								if (!file) {
									return { file_id, url: null, fallback_endpoint: null, expires_in: null, error: 'File not found' };
								}

								// Local storage: point to /content fallback
								if (file.provider === 'local') {
									const fallback = `${Config.server.backendUrl}/api/v1/files/${file_id}/content?mode=${modeValue}`;
									return { file_id, url: null, fallback_endpoint: fallback, expires_in: null };
								}

								if (!file.object_key) {
									return { file_id, url: null, fallback_endpoint: null, expires_in: null, error: 'No storage path' };
								}

								const expiresIn = 3600;
								const url = await storageAdapter.getSignedUrl(file.object_key, expiresIn, disposition);
								return { file_id, url, fallback_endpoint: null, expires_in: expiresIn };
							} catch {
								throw new GenericError('FILE_UPLOAD_FAILED');
							}
						}),
					);

					return sendSuccess(res, results);
				} catch (error) {
					return res.error(error);
				}
			},
		},
	};
};
