'use strict';

const WINDOW_BOUNDS_VERSION = 1;
const VIDEO_CHROME_WIDTH = 48;
const VIDEO_CHROME_HEIGHT = 246;
const MIN_WINDOW_WIDTH = 680;
const MIN_WINDOW_HEIGHT = 520;

function finiteBounds(bounds) {
  return Boolean(bounds) && ['x', 'y', 'width', 'height'].every((key) => Number.isFinite(bounds[key]));
}

function clamp(value, minimum, maximum) {
  return Math.min(Math.max(value, minimum), maximum);
}

function placeAroundCurrentCenter(width, height, currentBounds, workArea) {
  const centerX = finiteBounds(currentBounds)
    ? currentBounds.x + currentBounds.width / 2
    : workArea.x + workArea.width / 2;
  const centerY = finiteBounds(currentBounds)
    ? currentBounds.y + currentBounds.height / 2
    : workArea.y + workArea.height / 2;
  const maximumX = workArea.x + Math.max(0, workArea.width - width);
  const maximumY = workArea.y + Math.max(0, workArea.height - height);
  return {
    x: Math.round(clamp(centerX - width / 2, workArea.x, maximumX)),
    y: Math.round(clamp(centerY - height / 2, workArea.y, maximumY)),
    width,
    height,
  };
}

function videoWindowBounds({ sourceWidth, sourceHeight, zoom2x, scaleFactor, frameSize, currentBounds, workArea }) {
  const scale = Number.isFinite(scaleFactor) && scaleFactor > 0 ? scaleFactor : 1;
  const zoom = zoom2x ? 2 : 1;
  const frameWidth = Math.max(0, Number(frameSize?.width) || 0);
  const frameHeight = Math.max(0, Number(frameSize?.height) || 0);
  const contentWidth = Math.max(1, Number(sourceWidth) || 1) * zoom / scale + VIDEO_CHROME_WIDTH;
  const contentHeight = Math.max(1, Number(sourceHeight) || 1) * zoom / scale + VIDEO_CHROME_HEIGHT;
  const width = Math.min(workArea.width, Math.max(MIN_WINDOW_WIDTH, Math.round(contentWidth + frameWidth)));
  const height = Math.min(workArea.height, Math.max(MIN_WINDOW_HEIGHT, Math.round(contentHeight + frameHeight)));
  return placeAroundCurrentCenter(width, height, currentBounds, workArea);
}

function videoContentBounds({
  sourceWidth,
  sourceHeight,
  zoom2x,
  scaleFactor,
  frameSize,
  currentBounds,
  currentContentBounds,
  workArea,
}) {
  const scale = Number.isFinite(scaleFactor) && scaleFactor > 0 ? scaleFactor : 1;
  const zoom = zoom2x ? 2 : 1;
  const frameWidth = Math.max(0, Number(frameSize?.width) || 0);
  const frameHeight = Math.max(0, Number(frameSize?.height) || 0);
  const maximumContentWidth = Math.max(1, workArea.width - frameWidth);
  const maximumContentHeight = Math.max(1, workArea.height - frameHeight);
  const width = Math.min(maximumContentWidth, Math.max(MIN_WINDOW_WIDTH - frameWidth,
    Math.round(Math.max(1, Number(sourceWidth) || 1) * zoom / scale + VIDEO_CHROME_WIDTH)));
  const height = Math.min(maximumContentHeight, Math.max(MIN_WINDOW_HEIGHT - frameHeight,
    Math.round(Math.max(1, Number(sourceHeight) || 1) * zoom / scale + VIDEO_CHROME_HEIGHT)));
  const outer = placeAroundCurrentCenter(width + frameWidth, height + frameHeight, currentBounds, workArea);
  const insetX = finiteBounds(currentBounds) && finiteBounds(currentContentBounds)
    ? currentContentBounds.x - currentBounds.x
    : Math.floor(frameWidth / 2);
  const insetY = finiteBounds(currentBounds) && finiteBounds(currentContentBounds)
    ? currentContentBounds.y - currentBounds.y
    : Math.max(0, frameHeight - Math.floor(frameWidth / 2));
  return { x: outer.x + insetX, y: outer.y + insetY, width, height };
}

function resemblesLegacyVideoFit(bounds) {
  if (!finiteBounds(bounds)) return false;
  const mediaWidth = bounds.width - VIDEO_CHROME_WIDTH;
  const mediaHeight = bounds.height - VIDEO_CHROME_HEIGHT;
  if (mediaWidth < 320 || mediaHeight < 180) return false;
  const ratio = mediaWidth / mediaHeight;
  return [16 / 9, 4 / 3, 1, 9 / 16, 21 / 9].some((candidate) => Math.abs(ratio - candidate) < .06);
}

function migrateLegacyWindowBounds({ bounds, scaleFactor, frameSize, workArea }) {
  if (!resemblesLegacyVideoFit(bounds)) return finiteBounds(bounds) ? { ...bounds } : null;
  const scale = Number.isFinite(scaleFactor) && scaleFactor > 0 ? scaleFactor : 1;
  const frameWidth = Math.max(0, Number(frameSize?.width) || 0);
  const frameHeight = Math.max(0, Number(frameSize?.height) || 0);
  const legacyMediaWidth = bounds.width - VIDEO_CHROME_WIDTH;
  const legacyMediaHeight = bounds.height - VIDEO_CHROME_HEIGHT;
  const width = Math.min(workArea.width, Math.max(MIN_WINDOW_WIDTH,
    Math.round(legacyMediaWidth / scale + VIDEO_CHROME_WIDTH + frameWidth)));
  const height = Math.min(workArea.height, Math.max(MIN_WINDOW_HEIGHT,
    Math.round(legacyMediaHeight / scale + VIDEO_CHROME_HEIGHT + frameHeight)));
  return placeAroundCurrentCenter(width, height, bounds, workArea);
}

module.exports = {
  WINDOW_BOUNDS_VERSION,
  finiteBounds,
  migrateLegacyWindowBounds,
  resemblesLegacyVideoFit,
  videoContentBounds,
  videoWindowBounds,
};
