import {
  WALL_DIRECTIONS,
  OPENING_TYPES,
  DOOR_OPEN_DIRECTIONS,
  ELECTRICAL_TYPES,
  FURNITURE_TYPES,
  HORIZONTAL_ANCHORS,
  VERTICAL_ANCHORS,
  DEFAULT_POSITION_ANCHOR,
} from '@house-plan-maker/shared';
import type {
  Wall,
  WallOpening,
  ElectricalItem,
  FurnitureItem,
  Annotation,
  WallDirection,
  OpeningType,
  DoorOpenDirection,
  ElectricalType,
  FurnitureType,
  PositionAnchor,
  HorizontalAnchor,
  VerticalAnchor,
} from '@house-plan-maker/shared';

function toPositionAnchor(h: string | null | undefined, v: string | null | undefined): PositionAnchor {
  return {
    horizontal: validateEnum<HorizontalAnchor>(h ?? 'middle', HORIZONTAL_ANCHORS, DEFAULT_POSITION_ANCHOR.horizontal),
    vertical: validateEnum<VerticalAnchor>(v ?? 'middle', VERTICAL_ANCHORS, DEFAULT_POSITION_ANCHOR.vertical),
  };
}

/**
 * Parse a JSON string, returning the fallback on failure.
 * The fallback type is independent of T so that `null` can be passed.
 */
export function safeJsonParse<T, F = T>(value: string, fallback: F): T | F {
  try {
    return JSON.parse(value) as T;
  } catch {
    return fallback;
  }
}

function validateEnum<T extends string>(
  value: string,
  allowed: readonly T[],
  fallback: T,
): T {
  return (allowed as readonly string[]).includes(value) ? (value as T) : fallback;
}

export function toWallResponse(wall: {
  id: string;
  roomId: string;
  startX: number;
  startY: number;
  endX: number;
  endY: number;
  thickness: number;
  direction: string;
}): Wall {
  return {
    id: wall.id,
    roomId: wall.roomId,
    startX: wall.startX,
    startY: wall.startY,
    endX: wall.endX,
    endY: wall.endY,
    thickness: wall.thickness,
    direction: validateEnum<WallDirection>(wall.direction, WALL_DIRECTIONS, 'OTHER'),
  };
}

export function toOpeningResponse(opening: {
  id: string;
  roomId: string;
  wallId: string;
  type: string;
  positionAlongWall: number;
  width: number;
  height: number;
  elevationFromFloor: number;
  openDirection: string;
  anchorH?: string | null;
  anchorV?: string | null;
  gridCols?: number | null;
  gridRows?: number | null;
  slopeDepth?: number | null;
  frameThickness?: number | null;
}): WallOpening {
  return {
    id: opening.id,
    roomId: opening.roomId,
    wallId: opening.wallId,
    type: validateEnum<OpeningType>(opening.type, OPENING_TYPES, 'DOOR'),
    positionAlongWall: opening.positionAlongWall,
    width: opening.width,
    height: opening.height,
    elevationFromFloor: opening.elevationFromFloor,
    openDirection: validateEnum<DoorOpenDirection>(opening.openDirection, DOOR_OPEN_DIRECTIONS, 'LEFT'),
    positionAnchor: {
      horizontal: validateEnum<HorizontalAnchor>(opening.anchorH ?? 'middle', HORIZONTAL_ANCHORS, 'middle'),
      // Openings default to vertical=bottom (canonical: elevationFromFloor is the bottom edge).
      vertical: validateEnum<VerticalAnchor>(opening.anchorV ?? 'bottom', VERTICAL_ANCHORS, 'bottom'),
    },
    gridCols: Math.max(1, Math.min(10, Math.round(opening.gridCols ?? 2))),
    gridRows: Math.max(1, Math.min(10, Math.round(opening.gridRows ?? 2))),
    slopeDepth: Math.max(0, Math.min(2, opening.slopeDepth ?? 0)),
    frameThickness: Math.max(0, Math.min(0.5, opening.frameThickness ?? 0.03)),
  };
}

export function toElectricalResponse(item: {
  id: string;
  roomId: string;
  type: string;
  x: number;
  y: number;
  wallId: string | null;
  elevationFromFloor: number | null;
  rotation: number;
  count?: number | null;
  anchorH?: string | null;
  anchorV?: string | null;
  label?: string | null;
  metadata: string | null;
}): ElectricalItem {
  return {
    id: item.id,
    roomId: item.roomId,
    type: validateEnum<ElectricalType>(item.type, ELECTRICAL_TYPES, 'OUTLET'),
    x: item.x,
    y: item.y,
    wallId: item.wallId,
    elevationFromFloor: item.elevationFromFloor,
    rotation: item.rotation,
    count: Math.max(1, Math.round(item.count ?? 1)),
    positionAnchor: toPositionAnchor(item.anchorH, item.anchorV),
    label: item.label ?? null,
    metadata: item.metadata ? safeJsonParse<Record<string, unknown>, null>(item.metadata, null) : null,
  };
}

export function toFurnitureResponse(item: {
  id: string;
  roomId: string;
  type: string;
  x: number;
  y: number;
  width: number;
  depth: number;
  height: number;
  rotation: number;
  elevationFromFloor?: number | null;
  label: string | null;
  anchorH?: string | null;
  anchorV?: string | null;
  showProjection?: boolean | null;
  opacity?: number | null;
  metadata?: string | null;
}): FurnitureItem {
  return {
    id: item.id,
    roomId: item.roomId,
    type: validateEnum<FurnitureType>(item.type, FURNITURE_TYPES, 'OTHER'),
    x: item.x,
    y: item.y,
    width: item.width,
    depth: item.depth,
    height: item.height,
    rotation: item.rotation,
    elevationFromFloor: item.elevationFromFloor ?? 0,
    label: item.label,
    positionAnchor: toPositionAnchor(item.anchorH, item.anchorV),
    showProjection: item.showProjection ?? false,
    opacity: item.opacity ?? 1,
    metadata: item.metadata ? safeJsonParse<Record<string, unknown>, null>(item.metadata, null) : null,
  };
}

export function toAnnotationResponse(item: {
  id: string;
  roomId: string;
  x: number;
  y: number;
  text: string;
  fontSize: number | null;
  color: string | null;
  attachedToId: string | null;
  projectionOffsetX: number | null;
  projectionOffsetY: number | null;
}): Annotation {
  return {
    id: item.id,
    roomId: item.roomId,
    x: item.x,
    y: item.y,
    text: item.text,
    fontSize: item.fontSize ?? undefined,
    color: item.color ?? undefined,
    attachedToId: item.attachedToId ?? undefined,
    projectionOffsetX: item.projectionOffsetX ?? undefined,
    projectionOffsetY: item.projectionOffsetY ?? undefined,
  };
}
