import { z } from 'zod';
import {
  WALL_DIRECTIONS,
  OPENING_TYPES,
  DOOR_OPEN_DIRECTIONS,
  ELECTRICAL_TYPES,
  FURNITURE_TYPES,
  HORIZONTAL_ANCHORS,
  VERTICAL_ANCHORS,
} from '../types/elements.js';

// ── Position anchor ──

const positionAnchorSchema = z.object({
  horizontal: z.enum(HORIZONTAL_ANCHORS),
  vertical: z.enum(VERTICAL_ANCHORS),
});

// ── Wall schemas ──

const wallDirectionEnum = z.enum(WALL_DIRECTIONS);

const createWallItemSchema = z.object({
  startX: z.number(),
  startY: z.number(),
  endX: z.number(),
  endY: z.number(),
  thickness: z.number().positive('Thickness must be positive').optional(),
  direction: wallDirectionEnum.optional(),
});

/** Bulk update: replace all walls in a room. */
export const bulkUpdateWallsSchema = z.object({
  walls: z.array(createWallItemSchema),
});

export type BulkUpdateWallsInput = z.infer<typeof bulkUpdateWallsSchema>;

// ── WallOpening schemas ──

const openingTypeEnum = z.enum(OPENING_TYPES);
const doorOpenDirectionEnum = z.enum(DOOR_OPEN_DIRECTIONS);

export const createWallOpeningSchema = z.object({
  wallId: z.string().min(1, 'Wall ID is required'),
  type: openingTypeEnum,
  positionAlongWall: z.number().min(0, 'Position must be non-negative'),
  width: z.number().positive('Width must be positive'),
  height: z.number().positive('Height must be positive'),
  elevationFromFloor: z.number().min(0).optional(),
  openDirection: doorOpenDirectionEnum.optional(),
  positionAnchor: positionAnchorSchema.optional(),
  gridCols: z.number().int().min(1).max(10).optional(),
  gridRows: z.number().int().min(1).max(10).optional(),
  slopeDepth: z.number().min(0).max(2).optional(),
  frameThickness: z.number().min(0).max(0.5).optional(),
});

export const updateWallOpeningSchema = z.object({
  type: openingTypeEnum.optional(),
  positionAlongWall: z.number().min(0, 'Position must be non-negative').optional(),
  width: z.number().positive('Width must be positive').optional(),
  height: z.number().positive('Height must be positive').optional(),
  elevationFromFloor: z.number().min(0).optional(),
  openDirection: doorOpenDirectionEnum.optional(),
  positionAnchor: positionAnchorSchema.optional(),
  gridCols: z.number().int().min(1).max(10).optional(),
  gridRows: z.number().int().min(1).max(10).optional(),
  slopeDepth: z.number().min(0).max(2).optional(),
  frameThickness: z.number().min(0).max(0.5).optional(),
});

export type CreateWallOpeningInput = z.infer<typeof createWallOpeningSchema>;
export type UpdateWallOpeningInput = z.infer<typeof updateWallOpeningSchema>;

// ── ElectricalItem schemas ──

const electricalTypeEnum = z.enum(ELECTRICAL_TYPES);

export const createElectricalItemSchema = z.object({
  type: electricalTypeEnum,
  x: z.number(),
  y: z.number(),
  wallId: z.string().nullish(),
  elevationFromFloor: z.number().min(0).nullish(),
  rotation: z.number().min(0).max(360).optional(),
  count: z.number().int().min(1).max(20).optional(),
  positionAnchor: positionAnchorSchema.optional(),
  label: z.string().max(255).nullish(),
  metadata: z.record(z.string(), z.unknown()).nullish(),
});

export const updateElectricalItemSchema = z.object({
  type: electricalTypeEnum.optional(),
  x: z.number().optional(),
  y: z.number().optional(),
  wallId: z.string().nullish(),
  elevationFromFloor: z.number().min(0).nullish(),
  rotation: z.number().min(0).max(360).optional(),
  count: z.number().int().min(1).max(20).optional(),
  positionAnchor: positionAnchorSchema.optional(),
  label: z.string().max(255).nullish(),
  metadata: z.record(z.string(), z.unknown()).nullish(),
});

export type CreateElectricalItemInput = z.infer<typeof createElectricalItemSchema>;
export type UpdateElectricalItemInput = z.infer<typeof updateElectricalItemSchema>;

// ── FurnitureItem schemas ──

const furnitureTypeEnum = z.enum(FURNITURE_TYPES);

export const createFurnitureItemSchema = z.object({
  type: furnitureTypeEnum,
  x: z.number(),
  y: z.number(),
  width: z.number().positive('Width must be positive'),
  depth: z.number().positive('Depth must be positive'),
  height: z.number().positive('Height must be positive'),
  rotation: z.number().min(0).max(360).optional(),
  elevationFromFloor: z.number().min(0).optional(),
  label: z.string().max(255).nullish(),
  positionAnchor: positionAnchorSchema.optional(),
  showProjection: z.boolean().optional(),
  opacity: z.number().min(0).max(1).optional(),
  metadata: z.record(z.string(), z.unknown()).nullish(),
});

export const updateFurnitureItemSchema = z.object({
  type: furnitureTypeEnum.optional(),
  x: z.number().optional(),
  y: z.number().optional(),
  width: z.number().positive('Width must be positive').optional(),
  depth: z.number().positive('Depth must be positive').optional(),
  height: z.number().positive('Height must be positive').optional(),
  rotation: z.number().min(0).max(360).optional(),
  elevationFromFloor: z.number().min(0).optional(),
  label: z.string().max(255).nullish(),
  positionAnchor: positionAnchorSchema.optional(),
  showProjection: z.boolean().optional(),
  opacity: z.number().min(0).max(1).optional(),
  metadata: z.record(z.string(), z.unknown()).nullish(),
});

export type CreateFurnitureItemInput = z.infer<typeof createFurnitureItemSchema>;
export type UpdateFurnitureItemInput = z.infer<typeof updateFurnitureItemSchema>;

// ── Batch sync schemas ──

export const batchSyncOpeningsSchema = z.object({
  create: z.array(createWallOpeningSchema),
  update: z.array(
    z.object({
      id: z.string().min(1),
      data: updateWallOpeningSchema,
    }),
  ),
  delete: z.array(z.string().min(1)),
});

export type BatchSyncOpeningsInput = z.infer<typeof batchSyncOpeningsSchema>;

export const batchSyncElectricalSchema = z.object({
  create: z.array(createElectricalItemSchema),
  update: z.array(
    z.object({
      id: z.string().min(1),
      data: updateElectricalItemSchema,
    }),
  ),
  delete: z.array(z.string().min(1)),
});

export type BatchSyncElectricalInput = z.infer<typeof batchSyncElectricalSchema>;

export const batchSyncFurnitureSchema = z.object({
  create: z.array(createFurnitureItemSchema),
  update: z.array(
    z.object({
      id: z.string().min(1),
      data: updateFurnitureItemSchema,
    }),
  ),
  delete: z.array(z.string().min(1)),
});

export type BatchSyncFurnitureInput = z.infer<typeof batchSyncFurnitureSchema>;

// ── Annotation schemas ──

export const createAnnotationSchema = z.object({
  x: z.number(),
  y: z.number(),
  text: z.string().max(2000),
  fontSize: z.number().int().positive().max(96).optional(),
  color: z.string().max(32).optional(),
  attachedToId: z.string().nullish(),
  projectionOffsetX: z.number().nullish(),
  projectionOffsetY: z.number().nullish(),
});

export const updateAnnotationSchema = createAnnotationSchema.partial();

export const batchSyncAnnotationsSchema = z.object({
  create: z.array(createAnnotationSchema),
  update: z.array(
    z.object({
      id: z.string().min(1),
      data: updateAnnotationSchema,
    }),
  ),
  delete: z.array(z.string().min(1)),
});

export type CreateAnnotationInput = z.infer<typeof createAnnotationSchema>;
export type UpdateAnnotationInput = z.infer<typeof updateAnnotationSchema>;
export type BatchSyncAnnotationsInput = z.infer<typeof batchSyncAnnotationsSchema>;
