/**
 * Mailcow API Client — Alias & Mailbox Management
 *
 * Thin wrapper around Mailcow's REST API for creating/managing
 * forwarding aliases and real mailboxes on rspace.online.
 */

const MAILCOW_API_URL = process.env.MAILCOW_API_URL || 'http://nginx-mailcow:8080';
const MAILCOW_API_KEY = process.env.MAILCOW_API_KEY || '';

/** Check whether Mailcow integration is configured */
export function isMailcowConfigured(): boolean {
  return MAILCOW_API_KEY.length > 0;
}

async function mailcowFetch(path: string, options: RequestInit = {}): Promise<Response> {
  return fetch(`${MAILCOW_API_URL}${path}`, {
    ...options,
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': MAILCOW_API_KEY,
      ...options.headers,
    },
  });
}

/**
 * Create a forwarding alias.
 * Returns the Mailcow alias ID on success, or throws on failure.
 */
export async function createAlias(username: string, targetEmail: string): Promise<string> {
  const address = `${username}@rspace.online`;
  const res = await mailcowFetch('/api/v1/add/alias', {
    method: 'POST',
    body: JSON.stringify({
      address,
      goto: targetEmail,
      active: '1',
    }),
  });

  if (!res.ok) {
    const text = await res.text();
    throw new Error(`Mailcow createAlias failed (${res.status}): ${text}`);
  }

  // Mailcow returns an array with status objects; look up the alias ID
  const id = await findAliasId(address);
  if (!id) throw new Error('Alias created but could not retrieve ID');
  return id;
}

/**
 * Delete a forwarding alias by its Mailcow ID.
 */
export async function deleteAlias(aliasId: string): Promise<void> {
  const res = await mailcowFetch('/api/v1/delete/alias', {
    method: 'POST',
    body: JSON.stringify([aliasId]),
  });

  if (!res.ok) {
    const text = await res.text();
    throw new Error(`Mailcow deleteAlias failed (${res.status}): ${text}`);
  }
}

/**
 * Update the forwarding destination of an existing alias.
 */
export async function updateAlias(aliasId: string, newTargetEmail: string): Promise<void> {
  const res = await mailcowFetch(`/api/v1/edit/alias`, {
    method: 'POST',
    body: JSON.stringify({
      items: [aliasId],
      attr: {
        goto: newTargetEmail,
        active: '1',
      },
    }),
  });

  if (!res.ok) {
    const text = await res.text();
    throw new Error(`Mailcow updateAlias failed (${res.status}): ${text}`);
  }
}

/**
 * Find a Mailcow alias ID by its address (e.g. "alice@rspace.online").
 * Returns the ID string or null if not found.
 */
export async function findAliasId(address: string): Promise<string | null> {
  const res = await mailcowFetch('/api/v1/get/alias/all');

  if (!res.ok) {
    const text = await res.text();
    throw new Error(`Mailcow findAliasId failed (${res.status}): ${text}`);
  }

  const aliases: Array<{ id: number; address: string }> = await res.json();
  const match = aliases.find((a) => a.address === address);
  return match ? String(match.id) : null;
}

/**
 * Check whether an alias already exists for the given address.
 */
export async function aliasExists(address: string): Promise<boolean> {
  const id = await findAliasId(address);
  return id !== null;
}

// ── Mailbox Management ──

/**
 * Create a real Mailcow mailbox (not an alias).
 * Returns the generated password on success.
 */
export async function createMailbox(localPart: string, password: string): Promise<void> {
  const res = await mailcowFetch('/api/v1/add/mailbox', {
    method: 'POST',
    body: JSON.stringify({
      local_part: localPart,
      domain: 'rspace.online',
      password,
      password2: password,
      active: '1',
      quota: '256', // 256 MB — agent mailboxes are low-volume
      force_pw_update: '0',
      tls_enforce_in: '0',
      tls_enforce_out: '0',
    }),
  });

  if (!res.ok) {
    const text = await res.text();
    throw new Error(`Mailcow createMailbox failed (${res.status}): ${text}`);
  }

  // Mailcow returns [{type, log, msg}] — check for errors
  const body = await res.json();
  if (Array.isArray(body) && body[0]?.type === 'danger') {
    throw new Error(`Mailcow createMailbox error: ${JSON.stringify(body[0].msg)}`);
  }
}

/**
 * Delete a Mailcow mailbox by its address.
 */
export async function deleteMailbox(address: string): Promise<void> {
  const res = await mailcowFetch('/api/v1/delete/mailbox', {
    method: 'POST',
    body: JSON.stringify([address]),
  });

  if (!res.ok) {
    const text = await res.text();
    throw new Error(`Mailcow deleteMailbox failed (${res.status}): ${text}`);
  }
}

/**
 * Check whether a mailbox exists for the given address.
 */
export async function mailboxExists(address: string): Promise<boolean> {
  const res = await mailcowFetch(`/api/v1/get/mailbox/${encodeURIComponent(address)}`);
  if (!res.ok) return false;
  const data = await res.json();
  // Mailcow returns the mailbox object or an empty response
  return !!data && typeof data === 'object' && !Array.isArray(data) && !!data.username;
}
