import type { Mask } from '../Mask.js';
import type { Point } from '../utils/geometry/points.js';

import type { GetBorderPointsOptions } from './maskAnalysis.types.js';

// TODO: This function could be optimised by following the contour instead of scanning all pixels.
/**
 * Return an array with the coordinates of the pixels that are on the border of the mask.
 * The reference is the top-left corner of the ROI.
 * @param mask - Mask to process.
 * @param options - Get border points options.
 * @returns The array of border pixels.
 */
export function getBorderPoints(
  mask: Mask,
  options: GetBorderPointsOptions = {},
): Point[] {
  const { innerBorders = false, allowCorners = false } = options;

  if (!innerBorders) {
    mask = mask.solidFill();
  }

  const borders: Point[] = [];

  // first process frame pixels
  for (let column = 0; column < mask.width; column++) {
    if (mask.getBit(column, 0)) {
      borders.push({ column, row: 0 });
    }
    if (mask.getBit(column, mask.height - 1)) {
      borders.push({ column, row: mask.height - 1 });
    }
  }
  for (let row = 0; row < mask.height; row++) {
    if (mask.getBit(0, row)) {
      borders.push({ column: 0, row });
    }
    if (mask.getBit(mask.width - 1, row)) {
      borders.push({ column: mask.width - 1, row });
    }
  }

  for (let row = 1; row < mask.height - 1; row++) {
    for (let column = 1; column < mask.width - 1; column++) {
      if (mask.getBit(column, row)) {
        if (
          mask.getBit(column - 1, row) === 0 ||
          mask.getBit(column, row - 1) === 0 ||
          mask.getBit(column + 1, row) === 0 ||
          mask.getBit(column, row + 1) === 0
        ) {
          borders.push({ column, row });
        }

        if (
          allowCorners &&
          (mask.getBit(column - 1, row - 1) === 0 ||
            mask.getBit(column - 1, row + 1) === 0 ||
            mask.getBit(column + 1, row - 1) === 0 ||
            mask.getBit(column + 1, row + 1) === 0)
        ) {
          borders.push({ column, row });
        }
      }
    }
  }

  return borders;
}
