import type {
  AssetId,
  GraphNodeId,
  MaterialId,
  NpcGroupId,
  NpcId,
  NpcRelationId,
  ProjectId,
  SceneId,
} from './ids';
import type { MaterialLegend } from './materialLegend';
import type { SceneToken } from './appTokens';
import type { SceneNpcToken, PlayerImageOffset } from './appPlayers';
import type { NpcDisposition } from './npcDisposition';
import type { SceneGrid } from './sceneGrid';
import type { SceneTrap } from './sceneTraps';

export const PROJECT_SCHEMA_VERSION = 11 as const;

/** Материал кампании: изображение, показываемое поверх сцены во время игры. */
export type ProjectMaterial = {
  id: MaterialId;
  name: string;
  assetId: AssetId;
  rotationDeg: 0 | 90 | 180 | 270;
  /** Опциональная легенда (маркеры + список пунктов). */
  legend?: MaterialLegend;
};

/** Группа НПС (дерево через parentId). */
export type ProjectNpcGroup = {
  id: NpcGroupId;
  name: string;
  /** Hex `#rrggbb`. */
  color: string;
  parentId: NpcGroupId | null;
};

/** НПС кампании: персонаж с аватаром, описанием и связями на графе. */
export type ProjectNpc = {
  id: NpcId;
  name: string;
  avatarAssetId: AssetId;
  /** HTML-описание (TipTap), как у сцены. */
  description: string;
  /** Позиция карточки на графе взаимосвязей. */
  x: number;
  y: number;
  /** `null` — системная секция «Без группы». */
  groupId: NpcGroupId | null;
  /**
   * @deprecated Цвет кольца выводится из `disposition`. Поле оставлено для совместимости старых проектов.
   */
  ringColor: string;
  /** Дефолтный тип токена при постановке на карту. */
  disposition: NpcDisposition;
  /** Сдвиг аватара внутри круга токена. */
  imageOffset: PlayerImageOffset;
  /** Масштаб аватара внутри круга токена. */
  imageScale: number;
};

/** Однонаправленная связь: от `sourceNpcId` к `targetNpcId`; подпись на линии. */
export type ProjectNpcRelation = {
  id: NpcRelationId;
  sourceNpcId: NpcId;
  targetNpcId: NpcId;
  label: string;
};

export type IsoDateTimeString = string;

export type MediaAssetType = 'image' | 'video' | 'audio';

export type MediaAssetBase = {
  id: AssetId;
  type: MediaAssetType;
  mime: string;
  originalName: string;
  relPath: string;
  sha256: string;
  sizeBytes: number;
  createdAt: IsoDateTimeString;
};

export type ImageAsset = MediaAssetBase & {
  type: 'image';
  widthPx?: number;
  heightPx?: number;
};

export type VideoAsset = MediaAssetBase & {
  type: 'video';
  durationMs?: number;
  widthPx?: number;
  heightPx?: number;
};

export type AudioAsset = MediaAssetBase & {
  type: 'audio';
  durationMs?: number;
};

export type MediaAsset = ImageAsset | VideoAsset | AudioAsset;

/** Только видео и аудио сцены (изображения — только превью, отдельное поле). */
export type SceneAudioRef = {
  assetId: AssetId;
  autoplay: boolean;
  loop: boolean;
};

export type SceneMediaRefs = {
  videos: AssetId[];
  audios: SceneAudioRef[];
};

export type SceneSettings = {
  autoplayVideo: boolean;
  autoplayAudio: boolean;
  loopVideo: boolean;
  loopAudio: boolean;
};

export type SceneLayout = {
  x: number;
  y: number;
};

/** Узел на визуальном графе (одна сцена может иметь несколько узлов). */
export type SceneGraphNode = {
  id: GraphNodeId;
  sceneId: SceneId;
  x: number;
  y: number;
  /** Ровно один узел в проекте может быть начальной сценой для входа в граф. */
  isStartScene: boolean;
  /** Стартовый узел побочной сюжетной линии (синяя метка «ПОБОЧНАЯ»). */
  isSideStoryStart: boolean;
  /** Название побочной линии; только на узле с `isSideStoryStart`. */
  sideStoryLineTitle: string;
};

export type SceneGraphEdge = {
  id: string;
  sourceGraphNodeId: GraphNodeId;
  targetGraphNodeId: GraphNodeId;
};

export type Scene = {
  id: SceneId;
  title: string;
  description: string;
  /** Превью ассет (изображение или видео). */
  previewAssetId: AssetId | null;
  previewAssetType: 'image' | 'video' | null;
  /** Уменьшенное изображение для графа/списков; оригинал — в `previewAssetId`. */
  previewThumbAssetId: AssetId | null;
  /** Для видео-превью: автозапуск (в редакторе/списках/на графе). */
  previewVideoAutostart: boolean;
  /** Поворот превью в градусах (0/90/180/270). */
  previewRotationDeg: 0 | 90 | 180 | 270;
  /** В режиме показа: сцена начинается полностью затемнённой; мастер «раскрывает» кистью. */
  darkenScene: boolean;
  /** Ловушки на карте (только для image-превью); расстановка в проекте. */
  traps: SceneTrap[];
  /** Неигровые токены на карте (ссылки на app-local пул). */
  tokens: SceneToken[];
  /** Кампанийные НПС на карте как игровые токены (отдельно от неигровых). */
  npcTokens: SceneNpcToken[];
  /** Боевая сетка поверх превью (под ловушками/эффектами). */
  grid: SceneGrid;
  media: SceneMediaRefs;
  settings: SceneSettings;
  connections: SceneId[];
  layout: SceneLayout;
};

/** Запись о сюжетной линии в partial-экспорте (manifest в project.json). */
export type ExportedStorylineRef = {
  kind: 'main' | 'side';
  /** Для побочной линии — id стартового узла графа в этом архиве. */
  startGraphNodeId: GraphNodeId | null;
  label: string;
};

export type ProjectMeta = {
  name: string;
  /** Имя файла проекта без суффикса `.ttrpg.zip` (то, что пользователь редактирует). */
  fileBaseName: string;
  createdAt: IsoDateTimeString;
  updatedAt: IsoDateTimeString;
  /** Версия приложения, с которой проект был создан (не меняется при сохранениях). */
  createdWithAppVersion: string;
  /** Версия приложения при последнем сохранении. */
  appVersion: string;
  schemaVersion: typeof PROJECT_SCHEMA_VERSION;
};

export type Project = {
  id: ProjectId;
  meta: ProjectMeta;
  scenes: Record<SceneId, Scene>;
  /**
   * Порядок сцен в левом списке редактора (сверху вниз).
   * Если отсутствует или устарел — нормализуется при загрузке.
   */
  sceneListOrder: SceneId[];
  assets: Record<AssetId, MediaAsset>;
  /** Аудио кампании: играет в пульте на протяжении всей презентации, если в сцене нет своей музыки. */
  campaignAudios: SceneAudioRef[];
  /** Материалы кампании: изображения для показа поверх сцены (порядок = порядок в списке). */
  materials: ProjectMaterial[];
  /** НПС кампании (порядок = порядок в списке редактора/пульта). */
  npcs: ProjectNpc[];
  /** Группы НПС (порядок среди siblings = порядок в массиве). */
  npcGroups: ProjectNpcGroup[];
  /** Связи между НПС (однонаправленные; между одной парой направлений может быть несколько). */
  npcRelations: ProjectNpcRelation[];
  currentSceneId: SceneId | null;
  /** Текущая нода графа (важно, когда одна сцена имеет несколько нод). */
  currentGraphNodeId: GraphNodeId | null;
  /** Позиции карточек на графе; логические связи сцен по-прежнему в `Scene.connections`. */
  sceneGraphNodes: SceneGraphNode[];
  sceneGraphEdges: SceneGraphEdge[];
  /** При partial-экспорте: какие сюжетные линии включены в архив. */
  exportedStorylines?: ExportedStorylineRef[];
};
