import { Object3D, Ray, Vector3 } from 'three'

export class Face {
  constructor()
  normal: Vector3
  midpoint: Vector3
  area: number
  constant: number
  outside: VertexNode
  mark: number
  edge: HalfEdge

  static create(a: VertexNode, b: VertexNode, c: VertexNode): Face

  compute(): this
  getEdge(i: number): HalfEdge
}

export class HalfEdge {
  constructor(vertex: VertexNode, face: Face)
  vertex: VertexNode
  prev: HalfEdge
  next: HalfEdge
  twin: HalfEdge
  face: Face

  head(): VertexNode
  length(): number
  lengthSquared(): number
  setTwin(edge: HalfEdge): this
  tail(): VertexNode
}

export class VertexNode {
  constructor(point: Vector3)
  point: Vector3
  prev: VertexNode
  next: VertexNode
  face: Face
}

export class VertexList {
  constructor()
  head: VertexNode
  tail: VertexNode

  append(vertex: VertexNode): this
  appendChain(vertex: VertexNode): this
  clear(): this
  first(): VertexNode
  insertAfter(target: VertexNode, vertex: VertexNode): this
  insertBefore(target: VertexNode, vertex: VertexNode): this
  isEmpty(): boolean
  last(): VertexNode
  remove(vertex: VertexNode): this
  removeSubList(a: VertexNode, b: VertexNode): this
}

export class ConvexHull {
  constructor()
  tolerance: number
  faces: Face[]
  newFaces: Face[]
  assigned: VertexList
  unassigned: VertexList
  vertices: VertexNode[]

  addAdjoiningFace(eyeVertex: VertexNode, horizonEdge: HalfEdge): HalfEdge
  addNewFaces(eyeVertex: VertexNode, horizon: HalfEdge[]): this
  addVertexToFace(vertex: VertexNode, face: Face): this
  addVertexToHull(eyeVertex: VertexNode): this
  cleanup(): this
  compute(): this
  computeExtremes(): object
  computeHorizon(eyePoint: Vector3, crossEdge: HalfEdge, face: Face, horizon: HalfEdge[]): this
  computeInitialHull(): this
  containsPoint(point: Vector3): boolean
  deleteFaceVertices(face: Face, absorbingFace: Face): this
  intersectRay(ray: Ray, target: Vector3): Vector3 | null
  intersectsRay(ray: Ray): boolean
  makeEmpty(): this
  nextVertexToAdd(): VertexNode | undefined
  reindexFaces(): this
  removeAllVerticesFromFace(face: Face): VertexNode | undefined
  removeVertexFromFace(vertex: VertexNode, face: Face): this
  resolveUnassignedPoints(newFaces: Face[]): this
  setFromPoints(points: Vector3[]): this
  setFromObject(object: Object3D): this
}
