export type Atom = {
  NewVertex?: NewVertex;
  EdgeMap?: EdgeMap;
};

export type NewVertex = {
  up_context: Position[];
  down_context: Position[];
  flag: Flag;
};

export type Flag = { bits: number } | number;

export type Meta = { basename: string; metadata: number };

export function bits(f: Flag): number {
  return typeof f == 'number' ? f : f.bits;
}

export type Position = {
  change: number;
  pos: number;
};

export type Vertex = {
  change: number;
  start: number;
  end: number;
};

export type EdgeMap = {
  edges: Edge[];
  inode: Position;
};

export type Deps = null | { hashes: string[]; deps: string[]; known?: string[] };

export type Edge = {
  previous: Flag;
  flag: Flag;
  from: Position;
  to: Vertex;
  introduced_by: number;
};

export type Contents =
  | {
      Add: string;
    }
  | {
      Del: string;
    };

export type Hunk = {
  FileAdd?: {
    meta: Meta;
    context: Position[];
    contents: Contents[];
  };
  FileMove?: {
    old: Meta[];
    meta: Meta;
    up: Position[];
    down: Position[];
  };
  FileDel?: {
    deleted_names: Meta[];
    del: Atom;
    content_edges: Edge[];
    content: Contents[];
  };
  FileUndel?: {
    undel_names: Meta[];
    undel: Atom;
    content_edges: Edge[];
    content: Contents[];
  };
  SolveNameConflict?: {
    old: Meta[];
    name: Atom;
  };
  UnsolveNameConflict?: {
    old: Meta[];
    name: Atom;
  };
  Edit?: {
    path: string;
    line: number;
    atom: Atom;
    contents: Contents[];
  };
  Replacement?: {
    inode: number;
    path: string;
    line: number;
    ins: NewVertex;
    del: EdgeMap;
    ins_contents: Contents[];
    del_contents: Contents[];
  };
  SolveOrderConflict?: {
    path: string;
    line: number;
    atom: Atom;
    contents: Contents[];
  };
  UnsolveOrderConflict?: {
    path: string;
    line: number;
    atom: Atom;
    contents: Contents[];
  };
  ResurrectZombie?: {
    path: string;
    line: number;
    atom: Atom;
    contents: Contents[];
  };
  AddRoot?: {
    name: Atom;
    atom: Atom;
  };
  DelRoot?: {
    name: Atom;
    atom: Atom;
  };
};