import { Image } from '../Image.js';
import type { Mask } from '../Mask.js';

import { getDefaultColor } from './getDefaultColor.js';
import { assert } from './validators/assert.js';

/**
 * Blend the given pixel with the pixel at the specified location in the image.
 * @param image - The image with which to blend.
 * @param column - Column of the target pixel.
 * @param row - Row of the target pixel.
 * @param color - Color with which to blend the image pixel. Default: `Opaque black`.
 */

export function setBlendedPixel(
  image: Image | Mask,
  column: number,
  row: number,
  color?: number[],
) {
  color = color ?? getDefaultColor(image);

  if (!image.alpha) {
    image.setPixel(column, row, color);
  } else {
    assert(image instanceof Image);

    const sourceAlpha = color.at(-1) as number;

    if (sourceAlpha === image.maxValue) {
      image.setPixel(column, row, color);
      return;
    }

    const targetAlpha = image.getValue(column, row, image.channels - 1);

    const newAlpha =
      sourceAlpha + targetAlpha * (1 - sourceAlpha / image.maxValue);

    image.setValue(column, row, image.channels - 1, newAlpha);

    for (let component = 0; component < image.components; component++) {
      const sourceComponent = color[component];
      const targetComponent = image.getValue(column, row, component);

      const newComponent =
        (sourceComponent * sourceAlpha +
          targetComponent * targetAlpha * (1 - sourceAlpha / image.maxValue)) /
        newAlpha;

      image.setValue(column, row, component, newComponent);
    }
  }
}
