export const ACTIVE_DEV_PUBLIC_ENDPOINT = "http://74.48.78.17:16667";
export const ACTIVE_DEV_BROWSER_ENDPOINT = "http://74.48.78.17:16666";
export const DEPRECATED_DEV_PUBLIC_ENDPOINT = "http://74.48.78.17:6667";
export const DEPRECATED_RESERVED_PROD_ENDPOINT = "http://74.48.78.17:6666";
export const REPORT_LIFECYCLE_VERSION = "v1";

export const deprecatedPublicPorts = Object.freeze([6666, 6667]);
export const deprecatedPublicEndpoints = Object.freeze([
  DEPRECATED_DEV_PUBLIC_ENDPOINT,
  DEPRECATED_RESERVED_PROD_ENDPOINT
]);

const deprecatedPublicEndpointPattern = /\bhttps?:\/\/74\.48\.78\.17:(666[67])(?=[/?#\s"'`),\]}]|$)/giu;
const deprecatedPublicHostPortPattern = /(?<!\/\/)\b74\.48\.78\.17:(666[67])(?=[/?#\s"'`),\]}]|$)/giu;
const endpointContextWords = [
  "active",
  "api",
  "browser",
  "current",
  "deprecated",
  "edge",
  "endpoint",
  "frontend",
  "health",
  "historical",
  "ingress",
  "legacy",
  "public",
  "route"
].join("|");
const deprecatedPublicPortContextPattern = new RegExp(
  `\\b(?:${endpointContextWords})\\b[^.\\n]{0,80}(?<![A-Za-z0-9.-]):(666[67])\\b|(?<![A-Za-z0-9.-]):(666[67])\\b[^.\\n]{0,80}\\b(?:${endpointContextWords})\\b`,
  "giu"
);

function endpointForPort(port) {
  if (Number(port) === 6666) return DEPRECATED_RESERVED_PROD_ENDPOINT;
  if (Number(port) === 6667) return DEPRECATED_DEV_PUBLIC_ENDPOINT;
  throw new Error(`unsupported deprecated public port ${port}`);
}

function addMatches(matches, pattern, text) {
  pattern.lastIndex = 0;
  for (const match of String(text).matchAll(pattern)) {
    const port = match[1] ?? match[2];
    matches.add(endpointForPort(port));
  }
}

export function findDeprecatedPublicEndpoints(text) {
  const matches = new Set();
  addMatches(matches, deprecatedPublicEndpointPattern, text);
  addMatches(matches, deprecatedPublicHostPortPattern, text);
  addMatches(matches, deprecatedPublicPortContextPattern, text);
  return [...matches].sort();
}

export function isDeprecatedEndpointAllowedInActiveReport(report, endpoint) {
  const legacyEndpoint = report?.runtimeSmoke?.legacyPublicEndpoint;
  const deprecatedEndpoint = report?.deprecatedEndpoints?.find?.((item) => item?.endpoint === endpoint);
  return Boolean(
    (legacyEndpoint &&
      legacyEndpoint.endpoint === endpoint &&
      legacyEndpoint.status === "deprecated" &&
      legacyEndpoint.activeGreenEligible === false) ||
      (deprecatedEndpoint &&
        String(deprecatedEndpoint.status ?? "").includes("deprecated") &&
        deprecatedEndpoint.activeGreenEligible === false)
  );
}

export function findForbiddenActiveDeprecatedEndpoints(report, raw) {
  if (reportIsHistorical(report)) return [];
  return findDeprecatedPublicEndpoints(raw).filter(
    (endpoint) => !isDeprecatedEndpointAllowedInActiveReport(report, endpoint)
  );
}

export function reportLifecycleState(report) {
  return report?.reportLifecycle?.state ?? "active";
}

export function reportIsHistorical(report) {
  return reportLifecycleState(report) === "historical";
}

export function activeReportLifecycle(summary) {
  return {
    version: REPORT_LIFECYCLE_VERSION,
    state: "active",
    activeEndpoint: ACTIVE_DEV_PUBLIC_ENDPOINT,
    activeBrowserEndpoint: ACTIVE_DEV_BROWSER_ENDPOINT,
    deprecatedEndpoint: null,
    summary
  };
}

export function historicalReportLifecycle({ activeEndpoint = ACTIVE_DEV_PUBLIC_ENDPOINT, deprecatedEndpoint, summary }) {
  return {
    version: REPORT_LIFECYCLE_VERSION,
    state: "historical",
    activeEndpoint,
    activeBrowserEndpoint: ACTIVE_DEV_BROWSER_ENDPOINT,
    deprecatedEndpoint,
    summary
  };
}
