#!/usr/bin/env node
// DesignX CLI entry point
// Usage: npx designx [options]
//        designx [options]

import { spawn, exec } from 'node:child_process'
import { mkdirSync, existsSync, writeFileSync, unlinkSync } from 'node:fs'
import { join } from 'node:path'
import { homedir } from 'node:os'
import { createRequire } from 'node:module'
import { fileURLToPath } from 'node:url'

const __dirname = fileURLToPath(new URL('.', import.meta.url))
const require = createRequire(import.meta.url)
const { version } = require('../package.json')

// ── Argument parsing ──────────────────────────────────────────────────────────

const args = process.argv.slice(2)

function getArg(flag) {
  const eqIdx = args.findIndex((a) => a.startsWith(`${flag}=`))
  if (eqIdx !== -1) return args[eqIdx].slice(flag.length + 1)
  const spaceIdx = args.indexOf(flag)
  if (spaceIdx !== -1 && args[spaceIdx + 1] && !args[spaceIdx + 1].startsWith('-')) {
    return args[spaceIdx + 1]
  }
  return null
}

const PORT      = getArg('--port') ?? process.env.DESIGNX_PORT ?? '3000'
const DATA_DIR  = getArg('--data-dir') ?? process.env.DESIGNX_DATA_DIR ?? join(homedir(), 'DesignX')
const NO_OPEN   = args.includes('--no-open')

// ── Help / version ────────────────────────────────────────────────────────────

if (args.includes('--version') || args.includes('-v')) {
  console.log(`designx v${version}`)
  process.exit(0)
}

if (args.includes('--help') || args.includes('-h')) {
  console.log(`
  designx v${version}

  Usage: designx [options]

  Options:
    --port <port>         Port to listen on          (default: 3000)
    --data-dir <path>     Where to store all data     (default: ~/DesignX)
    --no-open             Do not open browser automatically
    --version, -v         Print version
    --help,    -h         Print this help
  `)
  process.exit(0)
}

// ── Data directory bootstrap ──────────────────────────────────────────────────

for (const dir of [
  DATA_DIR,
  join(DATA_DIR, 'projects'),
  join(DATA_DIR, 'data'),
]) {
  mkdirSync(dir, { recursive: true })
}

// ── Start server ──────────────────────────────────────────────────────────────

const serverPath = join(__dirname, '../server.cjs')

if (!existsSync(serverPath)) {
  console.error(
    '\n  [designx] server.cjs not found.\n' +
    '  Run `npm run package` inside the app directory to build it first.\n'
  )
  process.exit(1)
}

const child = spawn('node', [serverPath], {
  env: {
    ...process.env,
    PORT,
    NODE_ENV: 'production',
    DESIGNX_DATA_DIR: DATA_DIR,
    DESIGNX_UPDATE_FLAG: join(DATA_DIR, 'update-available.json'),
  },
  stdio: 'inherit',
})

child.on('error', (err) => {
  console.error('[designx] Failed to start server:', err.message)
  process.exit(1)
})

child.on('exit', (code) => {
  process.exit(code ?? 0)
})

process.on('SIGINT',  () => { child.kill('SIGINT');  process.exit(0) })
process.on('SIGTERM', () => { child.kill('SIGTERM'); process.exit(0) })

// ── Open browser ──────────────────────────────────────────────────────────────

const url = `http://localhost:${PORT}`

console.log(`\n  DesignX v${version}`)
console.log(`  Running at: ${url}`)
console.log(`  Data dir:   ${DATA_DIR}`)
console.log(`  Stop with:  Ctrl+C\n`)

if (!NO_OPEN) {
  setTimeout(() => {
    const cmd =
      process.platform === 'darwin'  ? `open "${url}"` :
      process.platform === 'win32'   ? `start "" "${url}"` :
                                       `xdg-open "${url}"`
    exec(cmd, (err) => {
      if (err) console.warn(`  [designx] Could not open browser: ${err.message}`)
    })
  }, 1800)
}

// ── Background update check ───────────────────────────────────────────────────
// Checks npm registry for the latest version. Non-blocking — runs after server
// starts. Writes ~/.designx/update-available.json when a newer version exists,
// which the server reads and exposes via GET /api/update-available.

const UPDATE_FLAG = join(DATA_DIR, 'update-available.json')

// Clear stale flag from previous run
try { unlinkSync(UPDATE_FLAG) } catch { /* doesn't exist — fine */ }

setTimeout(() => {
  exec('npm view @studioindia/designx version --json 2>/dev/null', { timeout: 10000 }, (err, stdout) => {
    if (err || !stdout) return
    try {
      const latest = JSON.parse(stdout.trim()).replace(/^"|"$/g, '')
      if (latest && latest !== version && isNewer(latest, version)) {
        writeFileSync(UPDATE_FLAG, JSON.stringify({ latest, current: version }), 'utf8')
        console.log(`  [designx] Update available: v${version} → v${latest}  (Relaunch to update)`)
      }
    } catch { /* malformed response */ }
  })
}, 3000) // wait 3 s to not slow perceived startup

// Re-check every 2 min so banner appears quickly after a new version is published
// (covers the case where a new version is published after app startup)
setInterval(() => {
  exec('npm view @studioindia/designx version --json 2>/dev/null', { timeout: 10000 }, (err, stdout) => {
    if (err || !stdout) return
    try {
      const latest = JSON.parse(stdout.trim()).replace(/^"|"$/g, '')
      if (latest && latest !== version && isNewer(latest, version)) {
        writeFileSync(UPDATE_FLAG, JSON.stringify({ latest, current: version }), 'utf8')
        console.log(`  [designx] Update available: v${version} → v${latest}  (Relaunch to update)`)
      }
    } catch { /* malformed response */ }
  })
}, 2 * 60 * 1000)

function isNewer(a, b) {
  const pa = a.split('.').map(Number)
  const pb = b.split('.').map(Number)
  for (let i = 0; i < 3; i++) {
    if ((pa[i] ?? 0) > (pb[i] ?? 0)) return true
    if ((pa[i] ?? 0) < (pb[i] ?? 0)) return false
  }
  return false
}
