import { z } from 'zod';
import {
  dateTransformSchema,
  defaultTransformSchema,
} from '../shared/shared.dto';

const optionalString = z.preprocess((value) => {
  if (typeof value === 'string' && value.trim() === '') return undefined;
  return value;
}, z.string().trim().optional());

const optionalDate = z.preprocess((value) => {
  if (value === null || value === undefined || value === '') return undefined;
  return value;
}, z.coerce.date().optional());

const optionalBool = z.preprocess((value) => {
  if (value === null || value === undefined || value === '') return undefined;
  if (typeof value === 'boolean') return value;
  if (typeof value === 'string') {
    const normalized = value.trim().toLowerCase();
    if (normalized === 'true') return true;
    if (normalized === 'false') return false;
  }
  return value;
}, z.boolean().optional());

const holidayTypeSchema = z.enum([
  'public',
  'company',
  'optional',
  'religious',
  'regional',
  'observance',
  'other',
]);

const departmentPreviewSchema = z.object({
  id: z.string().uuid(),
  name: z.string(),
  department_code: z.string(),
});

export const createHolidaySchema = z
  .object({
    name: z.string().trim().min(2, { message: 'Holiday name is required' }),
    holiday_type: holidayTypeSchema.optional(),
    start_date: z.coerce.date({ message: 'Start date is required' }),
    end_date: z.coerce.date({ message: 'End date is required' }),
    is_recurring: optionalBool,
    department_ids: z.array(z.string().uuid()).optional(),
    description: optionalString,
  })
  .refine((data) => data.end_date >= data.start_date, {
    path: ['end_date'],
    message: 'End date must be after or equal to start date',
  });

export const updateHolidaySchema = z
  .object({
    name: optionalString,
    holiday_type: holidayTypeSchema.optional(),
    start_date: optionalDate,
    end_date: optionalDate,
    is_recurring: optionalBool,
    department_ids: z.array(z.string().uuid()).optional(),
    description: optionalString,
  })
  .refine((data) => Object.keys(data).length > 0, {
    message: 'At least one field must be provided',
  })
  .refine(
    (data) =>
      !data.start_date || !data.end_date || data.end_date >= data.start_date,
    {
      path: ['end_date'],
      message: 'End date must be after or equal to start date',
    },
  );

export const holidayFilterSchema = z.object({
  start_date: optionalDate,
  end_date: optionalDate,
  from: optionalDate,
  to: optionalDate,
  holiday_type: holidayTypeSchema.optional(),
  department_id: z.preprocess((value) => {
    if (typeof value === 'string' && value.trim() === '') return undefined;
    return value;
  }, z.string().uuid().optional()),
  is_recurring: optionalBool,
  search: z.string().trim().optional(),
  page: z.preprocess((value) => {
    if (value === undefined || value === null || value === '') return 1;
    const parsed = Number(value);
    return Number.isNaN(parsed) ? value : parsed;
  }, z.number().int().min(1).default(1)),
  limit: z.preprocess((value) => {
    if (value === undefined || value === null || value === '') return 10;
    const parsed = Number(value);
    return Number.isNaN(parsed) ? value : parsed;
  }, z.number().int().min(1).max(100).default(10)),
  data_scope: z.enum(['own', 'all']).optional(),
});

export const holidayResponseSchema = z.object({
  id: z.string().uuid().optional(),
  name: z.string().optional(),
  holiday_type: holidayTypeSchema.optional(),
  start_date: z
    .date()
    .transform((date) => date.toISOString())
    .optional(),
  end_date: z
    .date()
    .transform((date) => date.toISOString())
    .optional(),
  occurrence_date: z.string().optional(),
  is_recurring: z.boolean().optional(),
  generated_from_recurring: z.boolean().optional(),
  description: defaultTransformSchema,
  departments: z.array(departmentPreviewSchema).optional(),
  created_at: dateTransformSchema,
  updated_at: dateTransformSchema,
});

export const holidaysResponseSchema = z.array(holidayResponseSchema);

export type createHolidayDto = z.infer<typeof createHolidaySchema>;
export type updateHolidayDto = z.infer<typeof updateHolidaySchema>;
export type holidayFilterDto = z.infer<typeof holidayFilterSchema>;
export type holidayResponseDto = z.infer<typeof holidayResponseSchema>;
export type holidaysResponseDto = z.infer<typeof holidaysResponseSchema>;
