import { number, string, z } from 'zod';
import type { components } from './openapi/schema';
import { arrayCoerce, commonQuerySchema, stringArrayCoerce, stringCoerce } from './common';

export type Book = components['schemas']['BookRead'];
export type BookFile = components['schemas']['FileMetadataRead'];
export type BookProgress = components['schemas']['BookProgressRead'];

export const bookQuerySchema = commonQuerySchema.extend({
	libraries: stringArrayCoerce,
	authors: stringArrayCoerce,
	publishers: stringArrayCoerce,
	tags: stringArrayCoerce,
	shelves: stringArrayCoerce,
	progress: arrayCoerce(z.enum(['unread', 'in_progress', 'read']))
		.nullable()
		.optional(),
	ids: stringArrayCoerce,
	cacheTimestamp: z.number().optional()
});

const identifiersSchema = z
	.string()
	.transform((str, ctx) => {
		try {
			return JSON.parse(str);
		} catch (e) {
			ctx.addIssue({
				code: 'custom',
				message: 'Must be a valid JSON string'
			});
			return z.NEVER;
		}
	})
	.pipe(
		z.record(z.string(), z.string()) // Key-value pairs, both strings
	);

export const editBookMetadataSchema = z.object({
	book_id: z.string(),
	title: string().min(1, 'Title cannot be empty'),
	subtitle: string().optional(),
	authors: z.array(z.string()).default([]),
	tags: z.array(z.string()).default([]),
	description: z.string().optional(),
	publisher: z.string().optional(),
	published_date: z
		.string()
		.optional()
		.transform((val) => (val ? new Date(val) : undefined)),
	series: z.string().optional(),
	series_position: z.string().optional(),
	identifiers: identifiersSchema,
	edition: z.number().optional(),
	pages: z.number().optional(),
	language: z.string().optional()
});

export const bookCoverUpload = z.object({
	book_id: stringCoerce,
	file: z.file()
});

export const booksUpload = z.object({
	library_id: stringCoerce,
	files: z.array(z.file()).min(1, 'At least one file must be uploaded')
});

export const bookFilesUpload = z.object({
	book_id: stringCoerce,
	files: z.array(z.file()).min(1, 'At least one file must be uploaded')
});

export const deleteBooksSchema = z.object({
	book_ids: stringArrayCoerce, // TODO Could also set minimum length of 1
	delete_files: z.boolean(),
	library_id: stringCoerce
});

export const bookIdsSchema = z.object({
	book_ids: stringArrayCoerce // TODO Could also set minimum length of 1
});

export const deleteBookFilesSchema = z.object({
	book_id: stringCoerce,
	file_ids: stringArrayCoerce,
	delete_files: z.boolean()
});

export const updateBookProgressSchema = z.object({
	book_ids: stringArrayCoerce,
	progress: number().min(0).max(1),
	completed: z.boolean().optional().default(false),
	epub_loc: z.string().optional(),
	pdf_loc: z.string().optional()
});

export type BookQuery = z.infer<typeof bookQuerySchema>;
export type BookEditMetadata = z.infer<typeof editBookMetadataSchema>;
export type DeleteBook = z.infer<typeof deleteBooksSchema>;
export type BookIds = z.infer<typeof bookIdsSchema>;
export type DeleteBookFiles = z.infer<typeof deleteBookFilesSchema>;
export type UpdateBookProgress = z.infer<typeof updateBookProgressSchema>;
