// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

import { Environment, getEnvironment } from '../environment.std.ts';
import type { LoggerType } from '../types/Logging.std.ts';
import { isNotUpdatable } from './version.std.ts';
import { isInPast } from './timestamp.std.ts';
import { DAY } from './durations/index.std.ts';

const NINETY_ONE_DAYS = 91 * DAY;
const THIRTY_ONE_DAYS = 31 * DAY;
const SIXTY_DAYS = 60 * DAY;

export type GetBuildExpirationTimestampOptionsType = Readonly<{
  version: string;
  packagedBuildExpiration: number;
  remoteBuildExpiration: number | undefined;
  autoDownloadUpdate: boolean;
  logger: LoggerType;
}>;

export function getBuildExpirationTimestamp({
  version,
  packagedBuildExpiration,
  remoteBuildExpiration,
  autoDownloadUpdate,
  logger,
}: GetBuildExpirationTimestampOptionsType): number {
  const localBuildExpiration =
    isNotUpdatable(version) || autoDownloadUpdate
      ? packagedBuildExpiration
      : packagedBuildExpiration - SIXTY_DAYS;

  // Log the expiration date in this selector because it invalidates only
  // if one of the arguments changes.
  let result: number;
  let type: string;
  if (remoteBuildExpiration && remoteBuildExpiration < localBuildExpiration) {
    type = 'remote';
    result = remoteBuildExpiration;
  } else {
    type = 'local';
    result = localBuildExpiration;
  }
  logger.info(`Build expires (${type}): ${new Date(result).toISOString()}`);
  return result;
}

export type HasBuildExpiredOptionsType = Readonly<{
  buildExpirationTimestamp: number;
  autoDownloadUpdate: boolean;
  now: number;
  logger: LoggerType;
}>;

export function hasBuildExpired({
  buildExpirationTimestamp,
  autoDownloadUpdate,
  now,
  logger,
}: HasBuildExpiredOptionsType): boolean {
  if (
    getEnvironment() !== Environment.PackagedApp &&
    buildExpirationTimestamp === 0
  ) {
    return false;
  }

  if (isInPast(buildExpirationTimestamp)) {
    return true;
  }

  const safeExpirationMs = autoDownloadUpdate
    ? NINETY_ONE_DAYS
    : THIRTY_ONE_DAYS;

  const buildExpirationDuration = buildExpirationTimestamp - now;
  const tooFarIntoFuture = buildExpirationDuration > safeExpirationMs;

  if (tooFarIntoFuture) {
    logger.error(
      'Build expiration is set too far into the future',
      buildExpirationTimestamp
    );
  }

  return tooFarIntoFuture || isInPast(buildExpirationTimestamp);
}
