import type { Point } from '../../geometry'
import type {
  NodeAnchorDefinition,
  NodeAnchorResolvedDefinition,
} from './index'
import { type ResolveOptions, resolve } from './util'

export interface MiddleSideEndpointOptions extends ResolveOptions {
  rotate?: boolean
  padding?: number
  direction?: 'H' | 'V'
}

const middleSide: NodeAnchorResolvedDefinition<MiddleSideEndpointOptions> = (
  view,
  magnet,
  refPoint,
  options,
) => {
  let bbox
  let angle = 0
  let center

  const node = view.cell
  if (options.rotate) {
    bbox = view.getUnrotatedBBoxOfElement(magnet)
    center = node.getBBox().getCenter()
    angle = node.getAngle()
  } else {
    if (node.visible) {
      bbox = view.getBBoxOfElement(magnet)
    } else {
      bbox = view.cell.getBBox()
    }
  }

  const padding = options.padding
  if (padding != null && Number.isFinite(padding)) {
    bbox.inflate(padding)
  }

  if (options.rotate) {
    refPoint.rotate(angle, center)
  }

  const side = bbox.getNearestSideToPoint(refPoint)
  let result: Point
  switch (side) {
    case 'left':
      result = bbox.getLeftMiddle()
      break
    case 'right':
      result = bbox.getRightMiddle()
      break
    case 'top':
      result = bbox.getTopCenter()
      break
    case 'bottom':
      result = bbox.getBottomCenter()
      break
    default:
      break
  }

  const direction = options.direction
  if (direction === 'H') {
    if (side === 'top' || side === 'bottom') {
      if (refPoint.x <= bbox.x + bbox.width) {
        result = bbox.getLeftMiddle()
      } else {
        result = bbox.getRightMiddle()
      }
    }
  } else if (direction === 'V') {
    if (refPoint.y <= bbox.y + bbox.height) {
      result = bbox.getTopCenter()
    } else {
      result = bbox.getBottomCenter()
    }
  }

  return options.rotate ? result!.rotate(-angle, center) : result!
}

/**
 * Places the anchor of the edge in the middle of the side of view bbox
 * closest to the other endpoint.
 */
export const midSide = resolve<
  NodeAnchorResolvedDefinition<ResolveOptions>,
  NodeAnchorDefinition<ResolveOptions>
>(middleSide)
