import type {
  CatalogEntry,
  DialogueChoice,
  DialogueFlowKind,
  DialogueFlowStep,
  DialogueSandbox,
  JsonObject,
  JsonValue,
} from "../editorCore";

export type ConditionValueRenderer = (conditionType: string, currentValue: string, onValueChange: (value: string) => void) => React.ReactNode;

export type ContentSectionContext = {
  activeType: string;
  setActiveType: (type: string) => void;
  setActiveSection: (section: "content" | "config") => void;
  records: JsonObject[];
  selectedIndex: number;
  isAllRecordsSelected: boolean;
  hasPendingRecordChanges: boolean;
  getRecordLabel: (record: JsonObject, index: number) => string;
  buildSpritePreviewDataUrl: (record: JsonObject, pixelSize: number) => string | null;
  normalizeHexColor: (value: JsonValue | undefined, fallback?: string) => string;
  selectRecordIndex: (index: number) => void;
  commitPendingRecordChanges: () => void;
  revertPendingRecordChanges: () => void;
  recordDraftError: string;
  isLoading: boolean;
  isSaving: boolean;
  selectedRecord: JsonObject | null;
  recordJsonDraft: string;
  jsonText: string;
  handleRawJsonEditorChange: (nextText: string) => void;
};

export type RecordEditorBaseContext = {
  isAllRecordsSelected: boolean;
  selectedRecord: JsonObject | null;
  activeEditTabs: string[];
  activeType: string;
  activeEditTab: string;
  setActiveEditTabByType: React.Dispatch<React.SetStateAction<Record<string, string>>>;
  selectedFieldEntriesForTab: Array<[string, JsonValue]>;
  isPlainObject: (value: JsonValue | undefined) => value is JsonObject;
  toFieldLabel: (rawKey: string) => string;
  handlePrimitiveFieldChange: (key: string, nextRaw: string) => void;
  npcTownOptions: string[];
  npcFactionOptions: Array<{ id: string; name: string }>;
  handleNpcPositionFieldChange: (axis: "x" | "y", nextRaw: string) => void;
  normalizeHexColor: (value: JsonValue | undefined, fallback?: string) => string;
  npcSpriteSearchQuery: string;
  setNpcSpriteSearchQuery: React.Dispatch<React.SetStateAction<string>>;
  filteredNpcSpriteOptions: JsonObject[];
  buildSpritePreviewDataUrl: (record: JsonObject, pixelSize: number) => string | null;
  npcSpriteOptions: JsonObject[];
  allNpcRecords: JsonObject[];
  allNpcTemplateRecords: JsonObject[];
  contentDataByType: Record<string, JsonObject>;
  patchSelectedRecord: (mutator: (record: JsonObject) => JsonObject) => void;
  activeSpritePaintSymbol: string;
  setActiveSpritePaintSymbol: React.Dispatch<React.SetStateAction<string>>;
  selectedSpriteEditorSize: { width: number; height: number };
  getSpriteCellSymbol: (record: JsonObject, x: number, y: number) => string;
  getSpritePalette: (record: JsonObject) => Record<string, string>;
  paintSpriteCell: (record: JsonObject, x: number, y: number, symbol: string) => JsonObject;
  colorPaletteEntries: CatalogEntry[];
};

export type ItemQuestAdvancedContext = {
  activeType: string;
  selectedRecord: JsonObject | null;
  activeEditTab: string;
  addItemActionEntry: () => void;
  selectedItemActions: JsonObject[];
  selectedIndex: number;
  isStepCollapsed: (stepId: string) => boolean;
  setStepCollapsed: (stepId: string, collapsed: boolean) => void;
  getItemActionSummary: (actionEntry: JsonObject, actionIndex: number) => string;
  moveItemActionEntry: (actionIndex: number, direction: -1 | 1) => void;
  deleteItemActionEntry: (actionIndex: number) => void;
  getPlainObjectArray: (value: JsonValue | undefined) => JsonObject[];
  patchSelectedRecordArray: (key: string, updater: (entries: JsonObject[]) => JsonObject[]) => void;
  patchItemActionFlowSteps: (actionIndex: number, updater: (steps: DialogueFlowStep[]) => DialogueFlowStep[]) => void;
  createFlowStep: (kind: DialogueFlowKind, namespace?: string) => DialogueFlowStep;
  FLOW_KIND_LABELS: Record<DialogueFlowKind, string>;
  getFlowStepSummary: (step: DialogueFlowStep) => string;
  conditionTypeOptions: string[];
  getDefaultConditionValue: (conditionType: string) => string;
  renderConditionValueField: ConditionValueRenderer;
  patchSelectedRecord: (mutator: (record: JsonObject) => JsonObject) => void;
  selectedQuestSteps: JsonObject[];
  getQuestStepSummary: (step: JsonObject, stepIndex: number) => string;
  moveQuestStepEntry: (stepIndex: number, direction: -1 | 1) => void;
  deleteQuestStepEntry: (stepIndex: number) => void;
  patchQuestSteps: (updater: (steps: JsonObject[]) => JsonObject[]) => void;
  addQuestStepEntry: () => void;
};

export type NpcDialogueEditorContext = {
  activeType: string;
  selectedRecord: JsonObject | null;
  activeEditTab: string;
  addDialogueNode: () => void;
  deleteDialogueNode: () => void;
  selectedDialogueNode: JsonObject | null;
  moveDialogueNode: (direction: -1 | 1) => void;
  selectedDialogueNodeIndex: number;
  dialogueNodes: JsonObject[];
  setSelectedDialogueNodeIndex: React.Dispatch<React.SetStateAction<number>>;
  selectedDialogueFieldEntries: Array<[string, JsonValue]>;
  toFieldLabel: (rawKey: string) => string;
  handleDialogueNodeFieldChange: (key: string, nextRaw: string) => void;
  patchFlowSteps: (updater: (steps: DialogueFlowStep[]) => DialogueFlowStep[]) => void;
  createFlowStep: (kind: DialogueFlowKind, namespace?: string) => DialogueFlowStep;
  selectedFlowSteps: DialogueFlowStep[];
  isStepCollapsed: (stepId: string) => boolean;
  dropTargetStepId: string;
  draggingStepId: string;
  setDraggingStepId: React.Dispatch<React.SetStateAction<string>>;
  setDropTargetStepId: React.Dispatch<React.SetStateAction<string>>;
  moveFlowStepById: (sourceStepId: string, targetStepId: string) => void;
  setStepCollapsed: (stepId: string, collapsed: boolean) => void;
  FLOW_KIND_LABELS: Record<DialogueFlowKind, string>;
  getFlowStepSummary: (step: DialogueFlowStep) => string;
  moveFlowStepByDirection: (stepId: string, direction: -1 | 1) => void;
  conditionTypeOptions: string[];
  getDefaultConditionValue: (conditionType: string) => string;
  renderConditionValueField: ConditionValueRenderer;
  dialogueNodeIds: string[];
  DIALOGUE_REACTION_TYPES: string[];
  simSandbox: DialogueSandbox;
  simCurrentNodeId: string;
  simText: string;
  simChoices: DialogueChoice[];
  simFallbackNextId: string;
  simEnded: boolean;
  startSimulation: () => void;
  updateSandbox: (nextSandbox: DialogueSandbox) => void;
  chooseSimChoice: (choice: DialogueChoice) => void;
  continueSimulation: () => void;
  isLoading: boolean;
  isSaving: boolean;
};

export type FullContentContext = ContentSectionContext & RecordEditorBaseContext & ItemQuestAdvancedContext & NpcDialogueEditorContext;
