import { z } from 'zod';
import { ApiResponseSchema, booleanFromString } from '#contracts/shared';

// ---------------------------------------------------------------------------
// Entity schemas
// ---------------------------------------------------------------------------

export const CompressInfoSchema = z
	.object({
		desktop: z.string().nullable().optional(),
		tablet: z.string().nullable().optional(),
		mobile: z.string().nullable().optional(),
		preload: z.string().nullable().optional(),
	})
	.openapi('CompressInfo');

export const FileSchema = z
	.object({
		id: z.uuid(),
		path: z.string(),
		name: z.string(),
		mime: z.string(),
		type: z.string(),
		size: z.number().int().nullable(),
		compress_info: CompressInfoSchema.nullable(),
		title: z.string().nullable(),
		description: z.string().nullable(),
		note: z.string().nullable(),
		is_library: z.boolean(),
		created_at: z.iso.datetime(),
		updated_at: z.iso.datetime().nullable(),
		created_by: z.uuid().nullable(),
		updated_by: z.uuid().nullable(),
	})
	.openapi('File');

export type FileRecord = z.infer<typeof FileSchema>;

// ---------------------------------------------------------------------------
// Request schemas
// ---------------------------------------------------------------------------

export const FileMutateBodySchema = z
	.object({
		title: z.string().max(150).nullable().optional().openapi({ example: 'Product Image' }),
		description: z.string().max(500).nullable().optional().openapi({ example: 'Main product image for homepage' }),
		note: z.string().max(255).nullable().optional().openapi({ example: 'Compressed version' }),
		is_library: z.boolean().optional().openapi({ example: false }),
	})
	.openapi('FileMutateBody');

export type FileMutateBody = z.infer<typeof FileMutateBodySchema>;

/** File upload (multipart/form-data) — `file` field is binary */
export const FileUploadBodySchema = z
	.object({
		file: z.string().openapi({ type: 'string', format: 'binary', description: 'File to upload' }),
		title: z.string().max(150).nullable().optional().openapi({ example: 'Product Image' }),
		description: z.string().max(500).nullable().optional().openapi({ example: 'Main product image' }),
		note: z.string().max(255).nullable().optional().openapi({ example: 'Compressed version' }),
		is_library: booleanFromString().optional().openapi({ example: false }),
	})
	.openapi('FileUploadBody');

/** File upload body validation schema (excludes `file` which is handled by multer) */
export const FileUploadBodyValidationSchema = FileUploadBodySchema.omit({ file: true });

/** File upload multiple body validation schema (excludes `files` which is handled by multer) */
export const FileUploadMultipleBodyValidationSchema = z
	.object({
		title: z.string().max(150).nullable().optional().openapi({ example: 'Product Image' }),
		description: z.string().max(500).nullable().optional().openapi({ example: 'Main product image' }),
		note: z.string().max(255).nullable().optional().openapi({ example: 'Compressed version' }),
		is_library: booleanFromString().optional().openapi({ example: false }),
	})
	.openapi('FileUploadMultipleBodyValidation');

// ---------------------------------------------------------------------------
// Paginated list
// ---------------------------------------------------------------------------

export const FileListDataSchema = z
	.object({
		count: z.number().int(),
		rows: z.array(FileSchema),
		page: z.number().int(),
		pageSize: z.number().int(),
	})
	.openapi('FileListData');

// ---------------------------------------------------------------------------
// Full response schemas (envelope + data)
// ---------------------------------------------------------------------------

export const FileResponseSchema = ApiResponseSchema(FileSchema).openapi('FileResponse');
export type FileResponse = z.infer<typeof FileResponseSchema>;

export const FileListResponseSchema = ApiResponseSchema(FileListDataSchema).openapi('FileListResponse');
export type FileListResponse = z.infer<typeof FileListResponseSchema>;

// ---------------------------------------------------------------------------
// Additional file operation schemas
// ---------------------------------------------------------------------------

export const FileArrayResponseSchema = ApiResponseSchema(z.array(FileSchema)).openapi('FileArrayResponse');
export type FileArrayResponse = z.infer<typeof FileArrayResponseSchema>;

export const RestoreFileResponseSchema = ApiResponseSchema(z.boolean()).openapi('RestoreFileResponse');
export type RestoreFileResponse = z.infer<typeof RestoreFileResponseSchema>;

// ---------------------------------------------------------------------------
// Additional file operation schemas
// ---------------------------------------------------------------------------

export const FileLinkResponseDataSchema = z
	.object({
		url: z.string().nullable(),
		fallback_endpoint: z.string().nullable(),
		expires_in: z.number().nullable(),
	})
	.openapi('FileLinkResponseData');

export const FileLinkResponseSchema = ApiResponseSchema(FileLinkResponseDataSchema).openapi('FileLinkResponse');
export type FileLinkResponse = z.infer<typeof FileLinkResponseSchema>;

export const QuotaResponseDataSchema = z
	.object({
		used_bytes: z.number().int(),
		used_files: z.number().int(),
		limit_bytes: z.number().nullable(),
	})
	.openapi('QuotaResponseData');

export const QuotaResponseSchema = ApiResponseSchema(QuotaResponseDataSchema).openapi('QuotaResponse');
export type QuotaResponse = z.infer<typeof QuotaResponseSchema>;

export const PresignResponseDataSchema = z
	.object({
		upload_url: z.string(),
		file_key: z.string(),
		upload_token: z.string(),
		expires_in: z.number(),
	})
	.openapi('PresignResponseData');

export const PresignResponseSchema = ApiResponseSchema(PresignResponseDataSchema).openapi('PresignResponse');
export type PresignResponse = z.infer<typeof PresignResponseSchema>;

export const PresignRequestSchema = z
	.object({
		file_name: z.string().openapi({ example: 'document.pdf' }),
		file_size: z.number().int().openapi({ example: 1048576 }),
		mime_type: z.string().openapi({ example: 'application/pdf' }),
	})
	.openapi('PresignRequest');

export const ConfirmFileRequestSchema = z
	.object({
		file_key: z.string().openapi({ example: 'uploads/2024/01/document.pdf' }),
		file_name: z.string().openapi({ example: 'document.pdf' }),
		file_size: z.number().int().openapi({ example: 1048576 }),
		mime_type: z.string().openapi({ example: 'application/pdf' }),
		upload_token: z.string().openapi({ example: 'upload_token_xyz123' }),
		title: z.string().optional().openapi({ example: 'Document' }),
		is_library: z.boolean().optional().openapi({ example: false }),
	})
	.openapi('ConfirmFileRequest');

export const BatchLinkRequestSchema = z
	.object({
		file_ids: z
			.array(z.uuid())
			.max(100)
			.openapi({
				example: ['550e8400-e29b-41d4-a716-446655440000', '550e8400-e29b-41d4-a716-446655440001'],
			}),
		mode: z.enum(['view', 'download']).default('view').optional(),
	})
	.openapi('BatchLinkRequest');

export const BatchLinkResultSchema = z
	.array(
		z.object({
			file_id: z.uuid(),
			url: z.string().nullable(),
			fallback_endpoint: z.string().nullable(),
			expires_in: z.number().nullable(),
			error: z.string().optional(),
		}),
	)
	.openapi('BatchLinkResult');

export const BatchLinkResponseSchema = ApiResponseSchema(BatchLinkResultSchema).openapi('BatchLinkResponse');
export type BatchLinkResponse = z.infer<typeof BatchLinkResponseSchema>;
