#!/usr/bin/env node

const fs = require('node:fs')
const path = require('node:path')
const { authenticator } = require('otplib')

function parseEnvFile(content) {
  const env = {}

  for (const rawLine of content.split(/\r?\n/)) {
    const line = rawLine.trim()
    if (!line || line.startsWith('#')) continue

    const normalized = line.startsWith('export ') ? line.slice(7).trim() : line
    const separatorIndex = normalized.indexOf('=')
    if (separatorIndex === -1) continue

    const key = normalized.slice(0, separatorIndex).trim()
    if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue

    let value = normalized.slice(separatorIndex + 1).trim()
    if (
      (value.startsWith('"') && value.endsWith('"')) ||
      (value.startsWith("'") && value.endsWith("'"))
    ) {
      const quote = value[0]
      value = value.slice(1, -1)
      if (quote === '"') {
        value = value
          .replace(/\\n/g, '\n')
          .replace(/\\r/g, '\r')
          .replace(/\\t/g, '\t')
          .replace(/\\"/g, '"')
          .replace(/\\\\/g, '\\')
      }
    }

    env[key] = value
  }

  return env
}

function loadLocalEnv() {
  const envPath = path.resolve(process.cwd(), '.env.local')
  if (!fs.existsSync(envPath)) return {}
  return parseEnvFile(fs.readFileSync(envPath, 'utf8'))
}

function normalizeApiBase(value) {
  const base = (value || 'http://localhost:4000').replace(/\/$/, '')
  return base.endsWith('/api/v1') ? base : `${base}/api/v1`
}

function updateCookieJar(cookieJar, setCookieHeaders) {
  for (const header of setCookieHeaders) {
    const pair = header.split(';')[0]
    const separatorIndex = pair.indexOf('=')
    if (separatorIndex === -1) continue

    const name = pair.slice(0, separatorIndex)
    const value = pair.slice(separatorIndex + 1)
    if (value) cookieJar.set(name, value)
    else cookieJar.delete(name)
  }
}

function cookieHeader(cookieJar) {
  return Array.from(cookieJar.entries())
    .map(([name, value]) => `${name}=${value}`)
    .join('; ')
}

async function request(apiBase, cookieJar, pathName, options = {}) {
  const headers = {
    ...(options.body ? { 'Content-Type': 'application/json' } : {}),
    ...(cookieJar.size ? { Cookie: cookieHeader(cookieJar) } : {}),
    ...options.headers,
  }

  const response = await fetch(`${apiBase}${pathName}`, {
    ...options,
    headers,
  })

  updateCookieJar(cookieJar, response.headers.getSetCookie?.() ?? [])

  const text = await response.text()
  let json = null
  if (text) {
    try {
      json = JSON.parse(text)
    } catch {
      throw new Error(`Non-JSON response from ${pathName}: ${text.slice(0, 200)}`)
    }
  }

  return { response, json }
}

async function main() {
  const localEnv = loadLocalEnv()
  const env = { ...localEnv, ...process.env }

  const email = env.ADMIN_SEED_EMAIL || 'admin@rentaldrivego.ma'
  const password = env.ADMIN_SEED_PASSWORD
  const apiBase = normalizeApiBase(env.NEXT_PUBLIC_API_URL || env.API_URL)

  if (!password || /^(placeholder|changeme|change-me)$/i.test(password)) {
    throw new Error('Set ADMIN_SEED_PASSWORD in .env.local or in the command environment.')
  }

  const cookieJar = new Map()

  const login = await request(apiBase, cookieJar, '/admin/auth/login', {
    method: 'POST',
    body: JSON.stringify({ email, password }),
  })

  if (!login.response.ok) {
    const error = login.json?.error || login.response.status
    if (error === 'totp_required') {
      throw new Error('This admin already has 2FA enabled. Use your authenticator or recovery code to sign in.')
    }
    throw new Error(login.json?.message || `Admin login failed: ${error}`)
  }

  const me = await request(apiBase, cookieJar, '/admin/auth/me')
  const admin = me.json?.data ?? me.json
  if (admin?.totpEnabled) {
    console.log(`Admin 2FA is already enabled for ${email}.`)
    return
  }

  const setup = await request(apiBase, cookieJar, '/admin/auth/2fa/setup', { method: 'POST' })
  if (!setup.response.ok) {
    throw new Error(setup.json?.message || 'Failed to create admin 2FA setup secret.')
  }

  const secret = setup.json?.data?.secret ?? setup.json?.secret
  if (!secret) throw new Error('2FA setup response did not include a secret.')

  const code = authenticator.generate(secret)
  const verify = await request(apiBase, cookieJar, '/admin/auth/2fa/verify', {
    method: 'POST',
    body: JSON.stringify({ code }),
  })

  if (!verify.response.ok) {
    throw new Error(verify.json?.message || 'Failed to verify generated 2FA code.')
  }

  const result = verify.json?.data ?? verify.json
  console.log(`Admin 2FA enabled for ${email}.`)
  console.log(`TOTP secret: ${secret}`)
  console.log('Add this secret to your authenticator app. The generated QR code data URL is available from /admin/auth/2fa/setup if you prefer scanning.')

  if (Array.isArray(result?.recoveryCodes) && result.recoveryCodes.length > 0) {
    console.log('\nRecovery codes:')
    for (const recoveryCode of result.recoveryCodes) console.log(`- ${recoveryCode}`)
  }
}

main().catch((error) => {
  console.error(error.message)
  process.exit(1)
})
