import { Paragraph, PID, WID, Word } from "./type";

export interface AddParagraphPayload {
  prevPid?: PID;
  pid: PID;
  paragraph: Paragraph;
}

export interface RemoveParagraphPayload {
  prevPid?: PID;
  pid: PID;
  paragraph: Paragraph;
}

export interface UpdateParagraphPayload {
  pid: PID;
  oldParagraph: Paragraph;
  paragraph: Paragraph;
}

export interface AddWordPayload {
  pid: PID;
  wid: WID;
  word: Word;
  oldOrder: WID[];
  newOrder: WID[];
}

export interface DeleteWordPayload {
  pid: PID;
  wid: WID;
  word: Word;
  oldOrder: WID[];
  newOrder: WID[];
}

export interface UpdateWordPayload {
  pid: PID;
  wid: WID;
  oldValue: Word;
  newValue: Word;
  userChangeText?: boolean;
}

export interface UpdateWordsPayload {
  pid: PID;
  oldValue: Word[];
  newValue: Word[];
}

export interface MoveWordPayload {
  originPid: PID;
  targetPid: PID;
  originOldOrder: WID[];
  originNewOrder: WID[];
  targetOldOrder: WID[];
  targetNewOrder: WID[];
}

export interface OperationPayloadMap {
  addParagraph: AddParagraphPayload;
  removeParagraph: RemoveParagraphPayload;
  updateParagraph: UpdateParagraphPayload;
  updateWord: UpdateWordPayload;
  updateWords: UpdateWordsPayload;
  addWord: AddWordPayload;
  deleteWord: DeleteWordPayload;
  moveWord: MoveWordPayload;
}

export type OpAction = keyof OperationPayloadMap;

export interface MapTo<T> {
  [key: string]: T;
}

export interface Operation<A = string, P = MapTo<any>> {
  action: A;
  payload: P;
}

export type OperationMap = {
  [A in OpAction]: Operation<A, OperationPayloadMap[A]>;
};

export type AnyOperation = OperationMap[OpAction];

export function createOperation<A extends OpAction>(action: A, payload: OperationPayloadMap[A]) {
  return {
    action,
    payload,
  };
}
