/**
 * Canonical name + domain derivation for workspace-scoped resources.
 *
 * AI-generated Coolify apps live under a single subdomain namespace
 * per workspace:
 *
 *   https://{app-slug}.{workspace-slug}.vibnai.com
 *
 * e.g. `api.mark.vibnai.com` for the `api` app in workspace `mark`.
 *
 * The DNS record `*.vibnai.com` (or its subdomain) must resolve to
 * the Coolify server. Traefik picks up the Host header and Coolify's
 * per-app ACME handshake provisions a Let's Encrypt cert per FQDN.
 */

const VIBN_BASE_DOMAIN = process.env.VIBN_BASE_DOMAIN ?? 'vibnai.com';
const SLUG_STRIP = /[^a-z0-9-]+/g;

/** Lowercase, dash-sanitize a free-form name into a DNS-safe slug. */
export function slugify(name: string): string {
  return name
    .toLowerCase()
    .replace(/[_\s]+/g, '-')
    .replace(SLUG_STRIP, '')
    .replace(/-+/g, '-')
    .replace(/^-+|-+$/g, '')
    .slice(0, 40) || 'app';
}

/**
 * The default public FQDN for an app inside a workspace, given the
 * workspace's slug (e.g. `mark`) and an app slug (e.g. `my-api`).
 *
 *   workspaceAppFqdn('mark', 'my-api') === 'my-api.mark.vibnai.com'
 */
export function workspaceAppFqdn(workspaceSlug: string, appSlug: string): string {
  return `${appSlug}-${workspaceSlug}.${VIBN_BASE_DOMAIN}`;
}

/** `https://{fqdn}` — what Coolify's `domains` field expects. */
export function toDomainsString(fqdns: string[]): string {
  return fqdns.map(f => (f.startsWith('http') ? f : `https://${f}`)).join(',');
}

/** Parse a Coolify `domains` CSV back into bare FQDNs. */
export function parseDomainsString(domains: string | null | undefined): string[] {
  if (!domains) return [];
  return domains
    .split(/[,\s]+/)
    .map(d => d.trim())
    .filter(Boolean)
    .map(d => d.replace(/^https?:\/\//, '').replace(/\/+$/, ''));
}

/** Guard against cross-workspace or disallowed domains. */
export function isDomainUnderWorkspace(fqdn: string, workspaceSlug: string): boolean {
  const f = fqdn.replace(/^https?:\/\//, '').toLowerCase();
  return f === `${workspaceSlug}.${VIBN_BASE_DOMAIN}` || f.endsWith(`-${workspaceSlug}.${VIBN_BASE_DOMAIN}`) || f.endsWith(`.${workspaceSlug}.${VIBN_BASE_DOMAIN}`);
}

/**
 * Build a Gitea SSH clone URL for a repo in a workspace's org.
 *
 * NOTE: As of 2026-04 this is deprecated for Coolify-driven deploys on
 * vibnai.com — Gitea's builtin SSH is bound to host port 22222 which is
 * not publicly reachable, and the default port 22 hits Ubuntu's host
 * sshd which doesn't know about Gitea keys. Use {@link giteaHttpsUrl}
 * instead and embed the workspace bot's PAT. Kept for read-only places
 * (e.g. UI display) that want the canonical "clone with SSH" form.
 */
export function giteaSshUrl(org: string, repo: string, giteaHost = 'git.vibnai.com'): string {
  return `git@${giteaHost}:${org}/${repo}.git`;
}

/**
 * Build a Gitea HTTPS clone URL with basic-auth credentials embedded.
 *
 *   https://{username}:{token}@{host}/{org}/{repo}.git
 *
 * This is what we pass to Coolify's `git_repository` field for every
 * Vibn-provisioned app. Works regardless of SSH topology and scopes
 * access to whatever the bot user can see. The token is usually the
 * per-workspace Gitea bot PAT.
 *
 * We URL-encode the username and token so PATs with special chars
 * (`:`, `/`, `@`, `#`, `?`, etc.) don't break URL parsing.
 */
export function giteaHttpsUrl(
  org: string,
  repo: string,
  username: string,
  token: string,
  giteaHost = 'git.vibnai.com'
): string {
  const u = encodeURIComponent(username);
  const t = encodeURIComponent(token);
  return `https://${u}:${t}@${giteaHost}/${org}/${repo}.git`;
}

/**
 * Redact the credentials from a Gitea HTTPS URL for safe logging /
 * display. Leaves the repo path intact. No-op for non-HTTPS URLs.
 */
export function redactGiteaHttpsUrl(url: string): string {
  return url.replace(/^(https?:\/\/)[^@]+@/, '$1***:***@');
}

export { VIBN_BASE_DOMAIN };
