import type { JsonObject } from "./contracts/json";

export const WORLD_INDEX_SCHEMA_VERSION = 1;
export const WORLD_SCHEMA_VERSION = 1;
export const WORLD_CHUNK_SCHEMA_VERSION = 1;
export const WORLD_BOOKMARKS_SCHEMA_VERSION = 1;
export const DEFAULT_WORLD_CHUNK_SIZE = 32;
export const DEFAULT_WORLD_TILE_SIZE = 32;

export type WorldIndexEntry = {
  id: string;
  name: string;
  worldDir: string;
};

export type WorldIndexPayload = {
  schemaVersion: number;
  worlds: WorldIndexEntry[];
};

export type WorldBookmark = {
  id: string;
  label: string;
  x: number;
  y: number;
};

export type WorldBookmarksPayload = {
  schemaVersion: number;
  worldId: string;
  bookmarks: WorldBookmark[];
};

export type WorldDefinition = {
  schemaVersion: number;
  id: string;
  name: string;
  chunkWidth: number;
  chunkHeight: number;
  tileSize: number;
  defaultBackgroundTileId: string;
  spawn: { x: number; y: number };
  editor?: {
    defaultZoom?: number;
    gridVisible?: boolean;
  };
};

export type WorldChunkLayer = {
  layer: number;
  name?: string;
  rows: string[];
  instanceIds: string[];
};

export type WorldHeightPatch = {
  id: string;
  name?: string;
  z: number;
  x: number;
  y: number;
  rows: string[];
};

export type WorldChunkInstance = {
  id: string;
  templateId?: string;
  layer: number;
  x: number;
  y: number;
  record: JsonObject;
};

export type WorldChunk = {
  schemaVersion: number;
  worldId: string;
  chunkX: number;
  chunkY: number;
  width: number;
  height: number;
  backgroundTileId: string;
  roomLayers: WorldChunkLayer[];
  heightLayers: WorldHeightPatch[];
  instances: WorldChunkInstance[];
};

export function normalizeChunkDimension(value: unknown, fallback = DEFAULT_WORLD_CHUNK_SIZE): number {
  return Math.max(1, Math.floor(Number(value) || fallback));
}

export function buildChunkKey(chunkX: number, chunkY: number): string {
  return `${Math.floor(chunkX)}:${Math.floor(chunkY)}`;
}

export function buildChunkFileName(chunkX: number, chunkY: number): string {
  return `${Math.floor(chunkX)}_${Math.floor(chunkY)}.json`;
}

export function worldToChunkCoord(worldCoord: number, chunkSize: number): number {
  const safeChunkSize = Math.max(1, Math.floor(Number(chunkSize) || DEFAULT_WORLD_CHUNK_SIZE));
  return Math.floor(Number(worldCoord) / safeChunkSize);
}

export function worldToLocalCoord(worldCoord: number, chunkSize: number): number {
  const safeChunkSize = Math.max(1, Math.floor(Number(chunkSize) || DEFAULT_WORLD_CHUNK_SIZE));
  const chunkCoord = worldToChunkCoord(worldCoord, safeChunkSize);
  return Math.floor(Number(worldCoord) - (chunkCoord * safeChunkSize));
}

export function localToWorldCoord(chunkCoord: number, localCoord: number, chunkSize: number): number {
  const safeChunkSize = Math.max(1, Math.floor(Number(chunkSize) || DEFAULT_WORLD_CHUNK_SIZE));
  return (Math.floor(Number(chunkCoord) || 0) * safeChunkSize) + Math.floor(Number(localCoord) || 0);
}

export function resolveWorldChunkAddress(worldX: number, worldY: number, chunkWidth: number, chunkHeight: number) {
  const safeChunkWidth = normalizeChunkDimension(chunkWidth);
  const safeChunkHeight = normalizeChunkDimension(chunkHeight);
  const chunkX = worldToChunkCoord(worldX, safeChunkWidth);
  const chunkY = worldToChunkCoord(worldY, safeChunkHeight);
  const localX = worldToLocalCoord(worldX, safeChunkWidth);
  const localY = worldToLocalCoord(worldY, safeChunkHeight);
  return {
    chunkX,
    chunkY,
    localX,
    localY,
    chunkKey: buildChunkKey(chunkX, chunkY),
    fileName: buildChunkFileName(chunkX, chunkY),
  };
}

export function createEmptyChunk(worldId: string, chunkX: number, chunkY: number, backgroundTileId = "", chunkWidth = DEFAULT_WORLD_CHUNK_SIZE, chunkHeight = DEFAULT_WORLD_CHUNK_SIZE): WorldChunk {
  const width = normalizeChunkDimension(chunkWidth);
  const height = normalizeChunkDimension(chunkHeight);
  return {
    schemaVersion: WORLD_CHUNK_SCHEMA_VERSION,
    worldId: String(worldId || "").trim(),
    chunkX: Math.floor(Number(chunkX) || 0),
    chunkY: Math.floor(Number(chunkY) || 0),
    width,
    height,
    backgroundTileId: String(backgroundTileId || "").trim(),
    roomLayers: [
      {
        layer: 0,
        rows: Array.from({ length: height }, () => ".".repeat(width)),
        instanceIds: [],
      },
      {
        layer: 1,
        rows: Array.from({ length: height }, () => " ".repeat(width)),
        instanceIds: [],
      },
    ],
    heightLayers: [],
    instances: [],
  };
}

