import { z } from "zod";
import {
  AllocationType,
  DispoImportSourceKind,
  DispoStagedRecordType,
  ImportBatchStatus,
  OrderType,
  ResourceType,
  StagedRecordStatus,
  VacationType,
} from "../types/enums.js";

const JsonRecordSchema = z.record(z.string(), z.unknown());
const StagedTraceSchema = z.object({
  importBatchId: z.string(),
  status: z.nativeEnum(StagedRecordStatus),
  sourceKind: z.nativeEnum(DispoImportSourceKind),
  sourceWorkbook: z.string().min(1),
  sourceSheet: z.string().min(1),
  sourceRow: z.number().int().nonnegative(),
  sourceColumn: z.string().min(1).optional().nullable(),
  warnings: z.array(z.string()).default([]),
  errorMessage: z.string().optional().nullable(),
  rawPayload: z.unknown(),
  normalizedData: JsonRecordSchema.default({}),
  createdAt: z.coerce.date(),
  updatedAt: z.coerce.date(),
});

export const ImportBatchSchema = z.object({
  id: z.string(),
  sourceSystem: z.string().min(1),
  status: z.nativeEnum(ImportBatchStatus),
  referenceSourceFile: z.string().optional().nullable(),
  planningSourceFile: z.string().optional().nullable(),
  chargeabilitySourceFile: z.string().optional().nullable(),
  notes: z.string().optional().nullable(),
  summary: JsonRecordSchema.default({}),
  startedAt: z.coerce.date().optional().nullable(),
  stagedAt: z.coerce.date().optional().nullable(),
  approvedAt: z.coerce.date().optional().nullable(),
  committedAt: z.coerce.date().optional().nullable(),
  failedAt: z.coerce.date().optional().nullable(),
  createdAt: z.coerce.date(),
  updatedAt: z.coerce.date(),
});

export const StagedResourceSchema = StagedTraceSchema.extend({
  id: z.string(),
  canonicalExternalId: z.string().min(1),
  enterpriseId: z.string().optional().nullable(),
  eid: z.string().optional().nullable(),
  displayName: z.string().optional().nullable(),
  email: z.string().email().optional().nullable(),
  chapter: z.string().optional().nullable(),
  chapterCode: z.string().optional().nullable(),
  managementLevelGroupName: z.string().optional().nullable(),
  managementLevelName: z.string().optional().nullable(),
  countryCode: z.string().optional().nullable(),
  metroCityName: z.string().optional().nullable(),
  clientUnitName: z.string().optional().nullable(),
  resourceType: z.nativeEnum(ResourceType).optional().nullable(),
  chargeabilityTarget: z.number().min(0).max(100).optional().nullable(),
  fte: z.number().min(0).max(1).optional().nullable(),
  lcrCents: z.number().int().min(0).optional().nullable(),
  ucrCents: z.number().int().min(0).optional().nullable(),
  availability: JsonRecordSchema.optional().nullable(),
  roleTokens: z.array(z.string()).default([]),
});

export const StagedClientSchema = StagedTraceSchema.extend({
  id: z.string(),
  clientCode: z.string().optional().nullable(),
  parentClientCode: z.string().optional().nullable(),
  name: z.string().min(1),
  sortOrder: z.number().int().optional().nullable(),
  isActive: z.boolean().default(true),
});

export const StagedProjectSchema = StagedTraceSchema.extend({
  id: z.string(),
  projectKey: z.string().min(1),
  shortCode: z.string().optional().nullable(),
  name: z.string().optional().nullable(),
  clientCode: z.string().optional().nullable(),
  utilizationCategoryCode: z.string().optional().nullable(),
  orderType: z.nativeEnum(OrderType).optional().nullable(),
  allocationType: z.nativeEnum(AllocationType).optional().nullable(),
  winProbability: z.number().int().min(0).max(100).optional().nullable(),
  isInternal: z.boolean().default(false),
  isTbd: z.boolean().default(false),
  startDate: z.coerce.date().optional().nullable(),
  endDate: z.coerce.date().optional().nullable(),
});

export const StagedAssignmentSchema = StagedTraceSchema.extend({
  id: z.string(),
  resourceExternalId: z.string().min(1),
  projectKey: z.string().optional().nullable(),
  assignmentDate: z.coerce.date().optional().nullable(),
  startDate: z.coerce.date().optional().nullable(),
  endDate: z.coerce.date().optional().nullable(),
  hoursPerDay: z.number().min(0).max(24).optional().nullable(),
  percentage: z.number().min(0).max(100).optional().nullable(),
  slotFraction: z.number().min(0).max(1).optional().nullable(),
  roleToken: z.string().optional().nullable(),
  roleName: z.string().optional().nullable(),
  chapterToken: z.string().optional().nullable(),
  utilizationCategoryCode: z.string().optional().nullable(),
  winProbability: z.number().int().min(0).max(100).optional().nullable(),
  isInternal: z.boolean().default(false),
  isUnassigned: z.boolean().default(false),
  isTbd: z.boolean().default(false),
});

export const StagedVacationSchema = StagedTraceSchema.extend({
  id: z.string(),
  resourceExternalId: z.string().min(1),
  vacationType: z.nativeEnum(VacationType),
  startDate: z.coerce.date(),
  endDate: z.coerce.date(),
  note: z.string().optional().nullable(),
  holidayName: z.string().optional().nullable(),
  isHalfDay: z.boolean().default(false),
  halfDayPart: z.string().optional().nullable(),
  isPublicHoliday: z.boolean().default(false),
});

export const StagedAvailabilityRuleSchema = StagedTraceSchema.extend({
  id: z.string(),
  resourceExternalId: z.string().min(1),
  ruleType: z.string().min(1),
  weekday: z.number().int().min(0).max(6).optional().nullable(),
  effectiveStartDate: z.coerce.date().optional().nullable(),
  effectiveEndDate: z.coerce.date().optional().nullable(),
  availableHours: z.number().min(0).max(24).optional().nullable(),
  percentage: z.number().min(0).max(100).optional().nullable(),
  isResolved: z.boolean().default(false),
});

export const StagedUnresolvedRecordSchema = z.object({
  id: z.string(),
  importBatchId: z.string(),
  status: z.nativeEnum(StagedRecordStatus),
  sourceKind: z.nativeEnum(DispoImportSourceKind),
  sourceWorkbook: z.string().min(1),
  sourceSheet: z.string().min(1),
  sourceRow: z.number().int().nonnegative(),
  sourceColumn: z.string().min(1).optional().nullable(),
  recordType: z.nativeEnum(DispoStagedRecordType),
  resourceExternalId: z.string().optional().nullable(),
  projectKey: z.string().optional().nullable(),
  message: z.string().min(1),
  resolutionHint: z.string().optional().nullable(),
  warnings: z.array(z.string()).default([]),
  rawPayload: z.unknown(),
  normalizedData: JsonRecordSchema.default({}),
  createdAt: z.coerce.date(),
  updatedAt: z.coerce.date(),
});

export type ImportBatchInput = z.infer<typeof ImportBatchSchema>;
export type StagedResourceInput = z.infer<typeof StagedResourceSchema>;
export type StagedClientInput = z.infer<typeof StagedClientSchema>;
export type StagedProjectInput = z.infer<typeof StagedProjectSchema>;
export type StagedAssignmentInput = z.infer<typeof StagedAssignmentSchema>;
export type StagedVacationInput = z.infer<typeof StagedVacationSchema>;
export type StagedAvailabilityRuleInput = z.infer<typeof StagedAvailabilityRuleSchema>;
export type StagedUnresolvedRecordInput = z.infer<typeof StagedUnresolvedRecordSchema>;
