'use strict';

const HASH = /^[a-f0-9]{64}$/;
const PLAN_SCHEMA = 'plai-production-data-replica-plan/v1';
const FORBIDDEN_KEY = /(password|secret|token|credential|cookie|connection.?string|mongo.?uri|private.?key|keyfile)/i;

function assertNoSecrets(value, valuePath = '$') {
  if (Array.isArray(value)) {
    value.forEach((entry, index) => assertNoSecrets(entry, `${valuePath}[${index}]`));
    return;
  }
  if (!value || typeof value !== 'object') return;
  for (const [key, entry] of Object.entries(value)) {
    if (FORBIDDEN_KEY.test(key)) throw new Error(`DATA_REPLICA_SECRET_FIELD_REJECTED:${valuePath}.${key}`);
    assertNoSecrets(entry, `${valuePath}.${key}`);
  }
}

function normalizeNode(row) {
  const nodeKeyId = String(row?.nodeKeyId || '').trim().toLowerCase();
  const networkFailureDomainCommitment = String(row?.networkFailureDomainCommitment || '').trim().toLowerCase();
  const controlPlaneFailureDomainCommitment = String(row?.controlPlaneFailureDomainCommitment || '').trim().toLowerCase();
  const storageRootCommitment = String(row?.storageRootCommitment || '').trim().toLowerCase();
  const transportEndpointCommitment = String(row?.transportEndpointCommitment || '').trim().toLowerCase();
  const endpointCertificateSpkiSha256 = String(row?.endpointCertificateSpkiSha256 || '').trim().toLowerCase();
  const minimumFreeBytes = Number(row?.minimumFreeBytes);
  if (!HASH.test(nodeKeyId) || !HASH.test(networkFailureDomainCommitment)
    || !HASH.test(controlPlaneFailureDomainCommitment) || !HASH.test(storageRootCommitment)
    || !HASH.test(transportEndpointCommitment) || !HASH.test(endpointCertificateSpkiSha256)
    || row?.privateTransportOnly !== true || row?.mutualTlsReady !== true
    || row?.diskEncryptionVerified !== true || row?.isolatedRestoreWorkspaceReady !== true
    || row?.productionAuthMaterialPresent !== false || row?.validatorRoleCoupled !== false
    || !/^8\.2\.\d+$/.test(String(row?.mongoVersion || ''))
    || !Number.isSafeInteger(minimumFreeBytes) || minimumFreeBytes < 20 * 1024 ** 3) {
    throw new Error('DATA_REPLICA_NODE_INVALID');
  }
  return {
    nodeKeyId,
    networkFailureDomainCommitment,
    controlPlaneFailureDomainCommitment,
    storageRootCommitment,
    transportEndpointCommitment,
    endpointCertificateSpkiSha256,
    privateTransportOnly: true,
    mutualTlsReady: true,
    diskEncryptionVerified: true,
    isolatedRestoreWorkspaceReady: true,
    productionAuthMaterialPresent: false,
    validatorRoleCoupled: false,
    mongoVersion: String(row.mongoVersion),
    minimumFreeBytes
  };
}

function validateProductionDataReplicaPlan(input, options = {}) {
  assertNoSecrets(input);
  const now = new Date(options.now || Date.now()).getTime();
  const issuedAt = new Date(input?.issuedAt || 0).getTime();
  const expiresAt = new Date(input?.expiresAt || 0).getTime();
  if (input?.schemaVersion !== PLAN_SCHEMA || input?.activationAllowed !== false
    || input?.productionBackupReadAllowed !== false || input?.externalCiphertextTransferAllowed !== false
    || input?.applicationWriteSwitchAllowed !== false || input?.productionDnsMutationAllowed !== false
    || input?.validatorMutationAllowed !== false || input?.operatorSigningAllowed !== false
    || input?.encryptedBackupOnly !== true || input?.plaintextBackupAllowed !== false
    || input?.writeConcern !== 'majority' || input?.readConcern !== 'majority'
    || input?.tlsMode !== 'requireTLS' || input?.authorizationRequired !== true
    || input?.maximumRpoSeconds !== 300 || input?.maximumRtoSeconds !== 1800
    || !/^[A-Za-z][A-Za-z0-9_-]{2,31}$/.test(String(input?.replicaSetName || ''))
    || !Number.isFinite(issuedAt) || !Number.isFinite(expiresAt) || issuedAt > now + 30_000
    || now - issuedAt > 10 * 60_000 || expiresAt <= now || expiresAt - issuedAt > 24 * 60 * 60_000) {
    throw new Error('DATA_REPLICA_PLAN_ENVELOPE_INVALID');
  }
  const nodes = (Array.isArray(input.nodes) ? input.nodes : []).map(normalizeNode);
  const unique = selector => new Set(nodes.map(selector)).size === nodes.length;
  if (nodes.length < 3 || nodes.length > 5 || !unique(row => row.nodeKeyId)
    || !unique(row => row.networkFailureDomainCommitment)
    || !unique(row => row.controlPlaneFailureDomainCommitment)
    || !unique(row => row.storageRootCommitment)
    || !unique(row => row.transportEndpointCommitment)
    || !unique(row => row.endpointCertificateSpkiSha256)) {
    throw new Error('DATA_REPLICA_THREE_INDEPENDENT_NODES_REQUIRED');
  }
  return {
    schemaVersion: PLAN_SCHEMA,
    issuedAt: new Date(issuedAt).toISOString(),
    expiresAt: new Date(expiresAt).toISOString(),
    replicaSetName: String(input.replicaSetName),
    activationAllowed: false,
    productionBackupReadAllowed: false,
    externalCiphertextTransferAllowed: false,
    applicationWriteSwitchAllowed: false,
    productionDnsMutationAllowed: false,
    validatorMutationAllowed: false,
    operatorSigningAllowed: false,
    encryptedBackupOnly: true,
    plaintextBackupAllowed: false,
    writeConcern: 'majority',
    readConcern: 'majority',
    tlsMode: 'requireTLS',
    authorizationRequired: true,
    maximumRpoSeconds: 300,
    maximumRtoSeconds: 1800,
    nodes
  };
}

function buildDefaultOffDataReplicaArtifacts(input, options = {}) {
  const plan = validateProductionDataReplicaPlan(input, options);
  return {
    schemaVersion: 'plai-production-data-replica-default-off-artifacts/v1',
    expiresAt: plan.expiresAt,
    activationAllowed: false,
    replicaSetPolicy: {
      name: plan.replicaSetName,
      votingMembers: plan.nodes.length,
      writeConcern: 'majority',
      readConcern: 'majority',
      tlsMode: 'requireTLS',
      authorizationRequired: true,
      memberNodeKeyIds: plan.nodes.map(row => row.nodeKeyId)
    },
    rehearsalPolicy: {
      productionBackupReadAllowed: false,
      externalCiphertextTransferAllowed: false,
      isolatedRestoreRequired: true,
      applicationWriteSwitchAllowed: false,
      nonSecretWriteCanaryAllowed: false
    },
    safety: {
      containsSecrets: false,
      plaintextBackupAllowed: false,
      productionChanged: false,
      validatorMutationAllowed: false,
      operatorSigningAllowed: false
    }
  };
}

module.exports = {
  PLAN_SCHEMA,
  validateProductionDataReplicaPlan,
  buildDefaultOffDataReplicaArtifacts
};
