'use strict';
/**
 * Auth profile resolver — Item C of multi-agent deep-dive.
 *
 * Borrowed shape from OpenClaw's per-cron-job authProfileId override
 * (src/cron/isolated-agent/run.ts:654). Wall-E's adaptation:
 *
 *   - auth_profiles table holds named profiles (name, type, credentials_kv_key)
 *   - skills.auth_profile_id FK overrides the default
 *   - profile resolver returns the actual credential bundle by reading
 *     the kv key
 *   - default profile (named 'default') wraps the existing global
 *     env-var/kv tokens — created automatically at boot
 *
 * Default behaviour: skills with auth_profile_id NULL use 'default'.
 * Existing skills + ingest/think/reflect loops are unchanged. Auth
 * profile is forward infrastructure for users who want multi-account
 * (work-slack + personal-slack, multiple gmail accounts, etc.).
 */
const brain = require('../brain');

const DEFAULT_PROFILE_NAME = 'default';

// Type → kv key mapping for the bundled 'default' profile.
// Each type can have multiple credentials (token, refresh_token, etc.) —
// we store them all under a single namespaced kv key as a JSON object
// for simplicity.
const DEFAULT_PROFILE_KV_KEY = 'auth_profile:default';

/**
 * Ensure the 'default' auth profile exists. Idempotent — safe to call
 * at every boot.
 */
function ensureDefaultProfile() {
  try {
    let profile = brain.getAuthProfileByName(DEFAULT_PROFILE_NAME);
    if (profile) return profile;
    const { id } = brain.insertAuthProfile({
      name: DEFAULT_PROFILE_NAME,
      type: 'multi',
      credentials_kv_key: DEFAULT_PROFILE_KV_KEY,
      metadata: {
        description: 'Default profile — wraps global env vars + existing kv tokens.',
        created_by: 'auth/profiles.js boot',
      },
    });
    return brain.getAuthProfile(id);
  } catch (err) {
    // If the migration hasn't run yet (test setup), don't crash — the
    // caller will use globals directly.
    if (/no such table|no such column/.test(err.message || '')) return null;
    throw err;
  }
}

/**
 * Resolve credentials for a skill (or for an ad-hoc `profileName` lookup).
 *
 * Returns an object describing where to find creds:
 *   { profile, credentials, source }
 * where:
 *   - profile is the auth_profiles row (or null if no profile, fallback to globals)
 *   - credentials is the parsed kv value (object) or null
 *   - source is 'profile' or 'globals' (when no profile bound)
 *
 * Skill-level resolution order:
 *   1. skill.auth_profile_id → look up by id
 *   2. skill metadata `auth_profile` (loader-level) → look up by name
 *   3. 'default' profile (auto-created)
 *   4. globals (env vars + bare kv keys like 'slack_token')
 */
function resolveSkillAuth(skill) {
  if (!skill) return { profile: null, credentials: null, source: 'globals' };

  // 1. by id (DB-driven binding)
  if (skill.auth_profile_id) {
    const profile = brain.getAuthProfile(skill.auth_profile_id);
    if (profile) return _resolveProfile(profile);
  }

  // 2. by name (loader-driven, comes from SKILL.md auth_profile field)
  // Caller is responsible for passing skill with .auth_profile set if
  // they want this resolution path.
  const name = skill.auth_profile || skill.auth_profile_name;
  if (name) {
    const profile = brain.getAuthProfileByName(name);
    if (profile) return _resolveProfile(profile);
  }

  // 3. default profile
  try {
    const def = brain.getAuthProfileByName(DEFAULT_PROFILE_NAME);
    if (def) return _resolveProfile(def);
  } catch {}

  // 4. globals fallback
  return { profile: null, credentials: null, source: 'globals' };
}

function _resolveProfile(profile) {
  let credentials = null;
  if (profile.credentials_kv_key) {
    try {
      const raw = brain.getKv(profile.credentials_kv_key);
      credentials = raw ? JSON.parse(raw) : null;
    } catch { credentials = null; }
  }
  return { profile, credentials, source: 'profile' };
}

/**
 * Convenience: load a profile by name + return its credentials.
 * Callers that already know the profile name (e.g. background jobs
 * binding to 'work-slack') can use this directly.
 */
function getCredentials(profileName) {
  const profile = brain.getAuthProfileByName(profileName);
  if (!profile) return null;
  const { credentials } = _resolveProfile(profile);
  return credentials;
}

/**
 * Helper for a specific credential type — returns the matching profile
 * + creds, or null if none. Callers like slack-ingest can do:
 *   const slackAuth = profiles.findFirstByType('slack')
 *   if (!slackAuth) return { error: 'no slack profile configured' }
 */
function findFirstByType(type) {
  try {
    const profiles = brain.listAuthProfiles({ type });
    if (!profiles || profiles.length === 0) return null;
    return _resolveProfile(profiles[0]);
  } catch { return null; }
}

module.exports = {
  ensureDefaultProfile,
  resolveSkillAuth,
  getCredentials,
  findFirstByType,
  DEFAULT_PROFILE_NAME,
  DEFAULT_PROFILE_KV_KEY,
};
