/**
 * Read the secret off a HostingConnection, whichever writer stored it.
 *
 * Two screens write to this collection and they do not agree on a cipher:
 *
 *   - routes/hostingConnections.ts (the "Connect" connectivity screen, shared by
 *     Landing Pages and the Website builder) stores `encrypt(secret)` from
 *     utils/encryption — AES-256-CBC, self-contained as `<iv hex>:<cipher hex>`.
 *
 *   - services/wordpress/WordPressConfigService.ts (Settings → Integrations, and
 *     the WordPress tab in the Blog module) stores `encryptApiKey(secret)` from
 *     services/utils/encryption — AES-256-GCM as `<cipher hex>:<tag hex>`, with
 *     the IV alongside in `providerData.iv`.
 *
 * Each reader understood only its own shape, so a WordPress site connected on
 * one screen was invisible to the other: it looked connected everywhere and
 * failed the moment anything tried to use it. Both are read here, so whichever
 * screen an admin used, the connection works.
 *
 * The two shapes are told apart by `providerData.iv` — its presence is the only
 * unambiguous signal, since a short secret's GCM ciphertext can coincidentally
 * match the CBC pattern.
 */

import { tryDecrypt } from '../../utils/encryption';
import { decryptApiKey } from '../utils/encryption';

/**
 * The decrypted secret, or '' when nothing readable is stored.
 *
 * '' rather than the ciphertext: handing a provider a string that merely looks
 * like a password produces a baffling 401 from the far end, whereas an empty
 * secret is caught by the "credentials are required" check the callers already
 * have.
 */
export function readConnectionSecret(connection: any): string {
  const secret: string | undefined = connection?.encryptedSecret;
  if (!secret) return '';

  // GCM (WordPress integration) — only when the separate IV is there to prove it.
  const iv = connection?.providerData?.iv;
  if (iv) {
    try {
      const value = decryptApiKey(secret, iv as string);
      if (value) return value;
    } catch {
      // Mis-tagged row — fall through and try the other shape.
    }
  }

  // CBC (hosting connectivity screen), plus the legacy plaintext case.
  try {
    const outcome = tryDecrypt(secret);
    if (outcome.ok && outcome.value) return outcome.value;

    // tryDecrypt() hands back an unrecognised value verbatim as `not-encrypted`,
    // which is how a genuinely plaintext legacy row still works. A GCM value
    // that lost its providerData.iv lands here too and must NOT be accepted —
    // hex is never a password anyone typed.
    if (!outcome.ok && outcome.reason === 'not-encrypted' && outcome.value
      && !outcome.value.includes(':') && !/^[0-9a-f]{16,}$/i.test(outcome.value)) {
      return outcome.value;
    }
  } catch {
    // Unreadable — fall through.
  }

  return '';
}

/**
 * Which cipher a connection's secret is already stored under.
 *
 * Used when re-saving an existing row: rewriting a hosting-screen connection's
 * secret in the other cipher would leave the deploy paths unable to read the
 * credential they were using a moment ago.
 */
export function connectionSecretScheme(connection: any): 'gcm' | 'cbc' {
  return connection?.providerData?.iv ? 'gcm' : 'cbc';
}
