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

export const attendanceTypeSchema = z.enum([
  'in_office',
  'remote',
  'on_duty',
  'flexible',
  'on_leave',
]);

export const attendanceStatusSchema = z.enum([
  'present',
  'absent',
  'late',
  'half_day',
  'on_leave',
  'remote',
  'check_in',
  'on_break',
  'holiday',
  'weekend',
  'all',
]);

const geoCoordinateSchema = z
  .union([z.number(), z.string()])
  .transform((val) =>
    val === null || val === undefined || val === '' ? undefined : Number(val),
  )
  .optional();

/**
 * Teacher Check-In payload
 */
export const teacherCheckInSchema = z.object({
  device_id: z.string().min(1, 'Device ID is required'),
  device_name: z.string().optional(),
  note: z.string().optional(),
  latitude: geoCoordinateSchema,
  longitude: geoCoordinateSchema,
  accuracy: z.number().optional(),
});

/**
 * Teacher Check-Out payload
 */
export const teacherCheckOutSchema = z.object({
  device_id: z.string().min(1, 'Device ID is required'),
  note: z.string().optional(),
  latitude: geoCoordinateSchema,
  longitude: geoCoordinateSchema,
  accuracy: z.number().optional(),
});

/**
 * Teacher Scan Static QR Attendance payload
 */
export const scanQrAttendanceSchema = z.object({
  qr_code: z.string().min(1, 'QR code is required'),
  device_id: z.string().min(1, 'Device ID is required'),
  device_name: z.string().optional(),
  note: z.string().optional(),
  latitude: geoCoordinateSchema,
  longitude: geoCoordinateSchema,
  accuracy: z.number().optional(),
});

/**
 * Admin QR Point Creation / Update schemas
 */
export const createQrPointSchema = z.object({
  label: z.string().min(1, 'Label is required'),
  is_active: z.boolean().optional().default(true),
});

export const updateQrPointSchema = z.object({
  label: z.string().optional(),
  is_active: z.boolean().optional(),
});

/**
 * Admin manual attendance payload
 */
export const adminManualAttendanceSchema = z.object({
  member_id: z.string().uuid('Invalid member ID'),
  date: z.string().or(z.date()),
  check_in: z.string().or(z.date()).optional().nullable(),
  check_out: z.string().or(z.date()).optional().nullable(),
  status: attendanceStatusSchema.optional().default('present'),
  work_hours: z.number().optional(),
  break_hours: z.number().optional(),
  net_hours: z.number().optional(),
  overtime_hours: z.number().optional(),
  note: z.string().optional(),
});

export const attendanceFilterSchema = z.object({
  page: z.coerce.number().optional(),
  limit: z.coerce.number().optional(),
  data_scope: z.enum(['all', 'own']).optional(),
  member_id: z.string().uuid().optional(),
  department_id: z.string().uuid().optional(),
  date: optionalDate,
  from: optionalDate,
  to: optionalDate,
  month_year: optionalDate,
  status: attendanceStatusSchema.optional().default('all'),
  search: z.string().optional(),
});

export const attendanceReportFilterSchema = z.object({
  start_date: optionalDate,
  end_date: optionalDate,
  department_id: z.string().uuid().optional(),
  search: z.string().optional(),
});

export const attendanceMemberSchema = z.object({
  id: z.string().uuid(),
  first_name: z.string(),
  last_name: defaultTransformSchema,
  nickname: defaultTransformSchema,
  employee_id: z.string(),
  role: z.enum(['owner', 'admin', 'member']).optional(),
  image: imageSchema.optional(),
  department: z
    .object({
      id: z.string().uuid(),
      name: z.string(),
    })
    .optional()
    .nullable(),
});

export const attendanceResponseSchema = z.object({
  id: z.string().uuid(),
  member_id: z.string().uuid(),
  member: attendanceMemberSchema.optional(),
  date: z
    .union([z.date(), z.string()])
    .transform((d) => (d instanceof Date ? d.toISOString().substring(0, 10) : String(d)))
    .optional(),
  type: z.string().optional(),
  check_in: z
    .date()
    .transform((date) => date.toISOString())
    .optional()
    .nullable(),
  check_out: z
    .date()
    .transform((date) => date.toISOString())
    .optional()
    .nullable(),
  work_hours: z.number().optional().nullable(),
  break_hours: z.number().optional().nullable(),
  net_hours: z.number().optional().nullable(),
  overtime_hours: z.number().optional().nullable(),
  status: attendanceStatusSchema.optional(),
  check_in_ip: nullableDefaultTransformSchema,
  check_out_ip: nullableDefaultTransformSchema,
  device_id: nullableDefaultTransformSchema,
  attendance_method: z.string().optional(),
  qr_point_id: nullableDefaultTransformSchema,
  check_in_latitude: z
    .union([z.number(), z.string()])
    .transform((val) =>
      val === null || val === undefined ? null : Number(val),
    )
    .nullable()
    .optional(),
  check_in_longitude: z
    .union([z.number(), z.string()])
    .transform((val) =>
      val === null || val === undefined ? null : Number(val),
    )
    .nullable()
    .optional(),
  check_in_distance_meters: z.number().nullable().optional(),
  check_out_latitude: z
    .union([z.number(), z.string()])
    .transform((val) =>
      val === null || val === undefined ? null : Number(val),
    )
    .nullable()
    .optional(),
  check_out_longitude: z
    .union([z.number(), z.string()])
    .transform((val) =>
      val === null || val === undefined ? null : Number(val),
    )
    .nullable()
    .optional(),
  check_out_distance_meters: z.number().nullable().optional(),
  note: defaultTransformSchema,
  created_at: dateTransformSchema,
  updated_at: dateTransformSchema,
});

export const attendancesResponseSchema = z.array(attendanceResponseSchema);

export const qrPointResponseSchema = z.object({
  id: z.string().uuid(),
  owner_id: z.string(),
  label: z.string(),
  code: z.string(),
  is_active: z.boolean(),
  qr_data_url: z.string().optional(),
  created_at: dateTransformSchema,
  updated_at: dateTransformSchema,
});

export const qrPointListResponseSchema = z.array(qrPointResponseSchema);

export const qrScanResultResponseSchema = z.object({
  action: z.enum(['CHECK_IN', 'CHECK_OUT', 'ALREADY_COMPLETED']),
  status: attendanceStatusSchema.optional(),
  check_in: z.string().optional().nullable(),
  check_out: z.string().optional().nullable(),
  work_hours: z.number().optional().nullable(),
  break_hours: z.number().optional().nullable(),
  net_hours: z.number().optional().nullable(),
  overtime_hours: z.number().optional().nullable(),
  attendance: attendanceResponseSchema.optional().nullable(),
  message: z.string(),
});

export const todayAttendanceItemSchema = z.object({
  member: attendanceMemberSchema,
  date: optionalDate,
  status: attendanceStatusSchema,
  is_submitted: z.boolean(),
  attendance: attendanceResponseSchema.nullable(),
});

export const todayAttendancesResponseSchema = z.array(
  todayAttendanceItemSchema,
);

export const attendanceReportResponseSchema = z.object({
  id: z.string().uuid(),
  first_name: z.string(),
  last_name: defaultTransformSchema,
  nickname: defaultTransformSchema,
  employee_id: z.string(),
  role: z.enum(['owner', 'admin', 'member']).optional(),
  image: imageSchema.optional(),
  department: z
    .object({
      id: z.string().uuid(),
      name: z.string(),
    })
    .optional()
    .nullable(),
  attendance_count: z.number(),
  late_count: z.number(),
  half_day_count: z.number(),
  leave_count: z.number(),
  absent_count: z.number(),
  total_working_days: z.number(),
  total_working_hours: z.number(),
  total_net_hours: z.number().optional(),
  total_overtime: z.number(),
  attendance_percentage: z.number().optional(),
  attendances: z.array(attendanceResponseSchema),
});

export const attendanceReportResponseArraySchema = z.array(
  attendanceReportResponseSchema,
);

export type TeacherCheckInDto = z.infer<typeof teacherCheckInSchema>;
export type TeacherCheckOutDto = z.infer<typeof teacherCheckOutSchema>;
export type ScanQrAttendanceDto = z.infer<typeof scanQrAttendanceSchema>;
export type CreateQrPointDto = z.infer<typeof createQrPointSchema>;
export type UpdateQrPointDto = z.infer<typeof updateQrPointSchema>;
export type QrPointResponseDto = z.infer<typeof qrPointResponseSchema>;
export type QrScanResultResponseDto = z.infer<typeof qrScanResultResponseSchema>;
export type AdminManualAttendanceDto = z.infer<
  typeof adminManualAttendanceSchema
>;
export type AttendanceFilterDto = z.infer<typeof attendanceFilterSchema>;
export type AttendanceReportFilterDto = z.infer<
  typeof attendanceReportFilterSchema
>;
export type AttendanceResponseDto = z.infer<typeof attendanceResponseSchema>;
export type AttendancesResponseDto = z.infer<typeof attendancesResponseSchema>;
export type TodayAttendanceResponseDto = z.infer<
  typeof todayAttendanceItemSchema
>;
export type TodayAttendancesResponseDto = z.infer<
  typeof todayAttendancesResponseSchema
>;
export type AttendanceReportResponseDto = z.infer<
  typeof attendanceReportResponseSchema
>;

// Compatibility aliases
export type createAttendanceDto = AdminManualAttendanceDto;
export type attendanceFilterDto = AttendanceFilterDto;
export type attendanceResponseDto = AttendanceResponseDto;
export type attendancesResponseDto = AttendancesResponseDto;
export type attendanceReportFilterDto = AttendanceReportFilterDto;
