#!/usr/bin/env node
/*
 * Seed a dev SSO provider + pre-linked identities — DEV ONLY.
 *
 * Registers an `auth_providers` row pointing at the local `stub-idp.js`, so
 * `GET /auth/providers` returns a provider and the native mobile SSO flow becomes
 * exercisable. Because SSO is link-only (identities are never auto-provisioned),
 * it also pre-links each stub principal's `sub` to an existing dev account.
 *
 * Idempotent: re-running upserts the provider and skips already-linked identities.
 *
 * Run (loads website/server/.env for DB creds):
 *   node website/scripts/dev/seed-sso-provider.js
 *
 * Env overrides:
 *   STUB_PROVIDER_ID     provider slug           (default 'devstub')
 *   STUB_IDP_PUBLIC_URL  browser-facing base     (default http://127.0.0.1:9099)
 *   STUB_IDP_INTERNAL_URL server-facing base     (default = STUB_IDP_PUBLIC_URL)
 *
 * The authorize URL is followed by the browser (Custom Tab); token/userinfo are
 * called server-side by the website. On an emulator set PUBLIC to the host's
 * reachable address (e.g. http://10.0.2.2:9099) and INTERNAL to http://127.0.0.1:9099.
 */

'use strict'

const fs = require('fs')
const path = require('path')

// Load website/server/.env into process.env WITHOUT the dotenv dependency (it
// lives in server/node_modules and wouldn't resolve from this scripts/ location).
// The file is simple KEY=value; that is all we need for the DB credentials.
function loadEnv(envPath) {
  if (!fs.existsSync(envPath)) return
  for (const line of fs.readFileSync(envPath, 'utf8').split(/\r?\n/)) {
    const m = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/.exec(line)
    if (!m) continue
    const key = m[1]
    let val = m[2].trim()
    if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
      val = val.slice(1, -1)
    }
    if (process.env[key] === undefined) process.env[key] = val
  }
}
loadEnv(path.join(__dirname, '..', '..', 'server', '.env'))

const authProviders = require('../../server/src/model/authProviders/authProviders.model')
const userIdentities = require('../../server/src/model/userIdentities/userIdentities.model')
const { close } = require('../../server/src/utils/db')

const PROVIDER_ID = process.env.STUB_PROVIDER_ID || 'devstub'
const PUBLIC_URL = (process.env.STUB_IDP_PUBLIC_URL || 'http://127.0.0.1:9099').replace(/\/$/, '')
const INTERNAL_URL = (process.env.STUB_IDP_INTERNAL_URL || PUBLIC_URL).replace(/\/$/, '')

// sub → dev account id. Keep the subs in sync with stub-idp.js PRINCIPALS.
const PRINCIPALS = [
  { sub: 'stub-admin', email: 'admin@dev.local', userId: 1 },
  { sub: 'stub-colby', email: 'colby@dev.local', userId: 14 },
]

async function main() {
  // eslint-disable-next-line no-console
  const log = (...a) => console.log('[seed-sso]', ...a)

  await authProviders.save(PROVIDER_ID, {
    kind: 'oauth2',
    name: 'Dev Stub IdP',
    enabled: true,
    clientId: 'stub-client',
    secret: 'stub-secret',
    authorizeUrl: `${PUBLIC_URL}/authorize`,
    tokenUrl: `${INTERNAL_URL}/token`,
    userinfoUrl: `${INTERNAL_URL}/userinfo`,
    scopes: 'openid email profile',
    priority: 50,
  })
  log(`provider '${PROVIDER_ID}' upserted (authorize=${PUBLIC_URL}/authorize, token/userinfo=${INTERNAL_URL})`)

  for (const p of PRINCIPALS) {
    const existing = await userIdentities.findByProviderSubject(PROVIDER_ID, p.sub)
    if (existing) {
      log(`identity ${PROVIDER_ID}:${p.sub} already linked to user ${existing.user_id} — skip`)
      continue
    }
    await userIdentities.link({ userId: p.userId, provider: PROVIDER_ID, subject: p.sub, email: p.email })
    log(`linked ${PROVIDER_ID}:${p.sub} → user ${p.userId}`)
  }

  log('done.')
}

main()
  .catch((err) => {
    // eslint-disable-next-line no-console
    console.error('[seed-sso] FAILED', err)
    process.exitCode = 1
  })
  .finally(async () => {
    try {
      await close()
    } catch {
      /* ignore shutdown errors */
    }
  })
