import type { SceneId } from './ids';

export const SCENE_TRAP_TYPES = [
  'mimic',
  'explosion',
  'poison',
  'pit',
  'arrow',
  'laser',
  'freeform',
] as const;

export type SceneTrapType = (typeof SCENE_TRAP_TYPES)[number];

export type SceneTrapId = string & { readonly __brand: 'SceneTrapId' };

export function asSceneTrapId(id: string): SceneTrapId {
  return id as SceneTrapId;
}

/** Расстановка ловушки на карте сцены (в проекте). Координаты 0..1 относительно картинки. */
export type SceneTrap = {
  id: SceneTrapId;
  type: SceneTrapType;
  /** Центр по X (0..1). */
  nx: number;
  /** Центр по Y (0..1). */
  ny: number;
  /** Размер относительно min(w,h) картинки. */
  sizeN: number;
  /** Подпись для freeform (и опционально прочих). */
  label?: string;
};

export type SceneTrapStatus = 'inactive' | 'active' | 'disarmed';

export type SceneTrapRuntime = {
  status: SceneTrapStatus;
  /** Показана игрокам (после Проявить / Активировать / Обезвредить). */
  revealed: boolean;
};

export type SceneTrapsState = {
  revision: number;
  cacheKey: string | null;
  /** runtime по id ловушки из Scene.traps */
  byId: Record<string, SceneTrapRuntime>;
  /**
   * Одноразовый VFX активации: id ловушки + token, чтобы презентация/пульт
   * могли проиграть анимацию при смене revision.
   */
  lastActivation: { trapId: string; token: number } | null;
};

export type SceneTrapsEvent =
  | { kind: 'reveal'; trapId: string }
  | { kind: 'activate'; trapId: string }
  | { kind: 'disarm'; trapId: string }
  | { kind: 'syncTrapIds'; trapIds: readonly string[] };

export const DEFAULT_SCENE_TRAP_SIZE_N = 0.08;

export function isSceneTrapType(v: unknown): v is SceneTrapType {
  return typeof v === 'string' && (SCENE_TRAP_TYPES as readonly string[]).includes(v);
}

export function defaultTrapRuntime(): SceneTrapRuntime {
  return { status: 'inactive', revealed: false };
}

export function clampTrapNorm(v: number): number {
  if (!Number.isFinite(v)) return 0.5;
  return Math.max(0, Math.min(1, v));
}

export function clampTrapSizeN(v: number): number {
  if (!Number.isFinite(v)) return DEFAULT_SCENE_TRAP_SIZE_N;
  return Math.max(0.02, Math.min(0.45, v));
}

export function normalizeSceneTrap(raw: unknown): SceneTrap | null {
  if (!raw || typeof raw !== 'object') return null;
  const o = raw as {
    id?: string;
    type?: string;
    nx?: number;
    ny?: number;
    sizeN?: number;
    label?: string;
  };
  if (!o.id || !isSceneTrapType(o.type)) return null;
  return {
    id: asSceneTrapId(String(o.id)),
    type: o.type,
    nx: clampTrapNorm(o.nx ?? 0.5),
    ny: clampTrapNorm(o.ny ?? 0.5),
    sizeN: clampTrapSizeN(o.sizeN ?? DEFAULT_SCENE_TRAP_SIZE_N),
    ...(typeof o.label === 'string' && o.label.trim() ? { label: o.label.trim() } : {}),
  };
}

export function trapTypeLabelRu(type: SceneTrapType): string {
  switch (type) {
    case 'mimic':
      return 'Мимик';
    case 'explosion':
      return 'Взрыв';
    case 'poison':
      return 'Яд';
    case 'pit':
      return 'Пропасть';
    case 'arrow':
      return 'Стрела';
    case 'laser':
      return 'Лазер';
    case 'freeform':
      return 'Метка';
    default: {
      const _x: never = type;
      return String(_x);
    }
  }
}

export type { SceneId };
