import fs from 'node:fs'
import os from 'node:os'
import path from 'node:path'
import { spawn, spawnSync } from 'node:child_process'
import http from 'node:http'
import { fileURLToPath } from 'node:url'

import { describe, expect, it } from 'vitest'

const currentFile = fileURLToPath(import.meta.url)
const websiteRoot = path.resolve(path.dirname(currentFile), '..')
const frontendProductionEnv = path.join(websiteRoot, '.env.production.example')
const frontendPreviewEnv = path.join(websiteRoot, '.env.preview.example')
const serverProductionEnv = path.join(websiteRoot, 'server', '.env.production.example')
const serverPreviewEnv = path.join(websiteRoot, 'server', '.env.preview.example')
const runtimeReadinessScript = path.join(websiteRoot, 'scripts', 'check-runtime-readiness.mjs')

function runCli(args, options = {}) {
  return new Promise((resolve, reject) => {
    const child = spawn(process.execPath, args, {
      cwd: websiteRoot,
      stdio: ['ignore', 'pipe', 'pipe'],
      ...options,
    })

    let stdout = ''
    let stderr = ''
    child.stdout.on('data', (chunk) => {
      stdout += chunk
    })
    child.stderr.on('data', (chunk) => {
      stderr += chunk
    })
    child.on('error', reject)
    child.on('close', (status) => {
      resolve({
        status,
        stdout,
        stderr,
      })
    })
  })
}

describe('check-runtime-readiness CLI', () => {
  it('fails the real production example env files until placeholder launch values are replaced', () => {
    const result = spawnSync(
      process.execPath,
      [
        runtimeReadinessScript,
        '--frontend-env',
        frontendProductionEnv,
        '--server-env',
        serverProductionEnv,
        '--skip-live-health',
        '--json',
      ],
      {
        cwd: websiteRoot,
        encoding: 'utf8',
      },
    )

    expect(result.status).toBe(1)
    expect(result.stderr).toBe('')

    const report = JSON.parse(result.stdout)
    expect(report.ok).toBe(false)
    expect(report.failures).toContain('VITE_WINDOWS_DOWNLOAD_URL still contains a placeholder value.')
    expect(report.failures).toContain('VITE_PADDLE_CHECKOUT_URL_OPERATOR still contains a placeholder value.')
    expect(report.failures).toContain('VITE_MPL_SOURCE_URL still contains a placeholder value.')
    expect(report.failures).toContain('PADDLE_WEBHOOK_SECRET still contains a placeholder value.')
    expect(report.failures).toContain('PADDLE_PRODUCT_PLAN_MAP still contains a placeholder value.')
    expect(report.failures).toContain('PADDLE_PRICE_PLAN_MAP still contains a placeholder value.')
  })

  it('passes the real preview example env files while preserving honest preview warnings', () => {
    const result = spawnSync(
      process.execPath,
      [
        runtimeReadinessScript,
        '--frontend-env',
        frontendPreviewEnv,
        '--server-env',
        serverPreviewEnv,
        '--skip-live-health',
        '--json',
      ],
      {
        cwd: websiteRoot,
        encoding: 'utf8',
      },
    )

    expect(result.status).toBe(0)
    expect(result.stderr).toBe('')

    const report = JSON.parse(result.stdout)
    expect(report.ok).toBe(true)
    expect(report.failures).toEqual([])
    expect(report.deploymentTier).toBe('preview')
    expect(report.warnings).toContain('VITE_WINDOWS_DOWNLOAD_URL or WINDOWS_DOWNLOAD_URL is not set; Windows download will remain in preview posture until the release lane is configured.')
    expect(report.warnings).toContain('VITE_PADDLE_CHECKOUT_URL_OPERATOR is not set; Operator pricing will stay on the support fallback until checkout is configured.')
    expect(report.warnings).toContain('PADDLE_WEBHOOK_SECRET is not set; billing webhook handling will remain in preview posture until the live secret is configured.')
  })

  it('fails a live deployment probe when the public origin still serves the placeholder page instead of JSON routes', async () => {
    const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'hypertwist-runtime-readiness-'))
    const frontendEnv = path.join(tempDir, 'frontend.env')
    const serverEnv = path.join(tempDir, 'server.env')

    fs.writeFileSync(frontendEnv, `
VITE_SUPERTOKENS_API_DOMAIN=https://hypertwist.app
VITE_SUPERTOKENS_WEBSITE_DOMAIN=https://hypertwist.app
VITE_AUTH_API_BASE_URL=https://hypertwist.app
VITE_WINDOWS_DOWNLOAD_URL=https://downloads.hypertwist.app/windows.exe
VITE_PADDLE_CHECKOUT_URL_OPERATOR=https://buy.paddle.com/operator
VITE_PADDLE_CHECKOUT_URL_STUDIO=https://buy.paddle.com/studio
VITE_MPL_SOURCE_URL=https://hypertwist.app/open-source/source
VITE_OPEN_SOURCE_REPO_URL=https://git.scriptoriumai.io/scriptoriumadmin/hypertwist
`)
    fs.writeFileSync(serverEnv, `
API_DOMAIN=https://hypertwist.app
WEBSITE_DOMAIN=https://hypertwist.app
SUPERTOKENS_CORE_URI=https://auth-core.internal
COOKIE_SECURE=true
SERVE_STATIC_WEBSITE=true
PADDLE_WEBHOOK_SECRET=secret
PADDLE_PRICE_PLAN_MAP={"pri_operator":"operator"}
`)

    const placeholderHtml = `<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>HyperTwist</title>
  </head>
  <body>
    <main>
      <h1>HyperTwist</h1>
      <p>Deployment target is live on the new VPS. Application rollout is pending.</p>
    </main>
  </body>
</html>`

    const server = http.createServer((req, res) => {
      res.writeHead(200, { 'content-type': 'text/html; charset=utf-8' })
      res.end(placeholderHtml)
    })

    await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve))
    const address = server.address()
    if (!address || typeof address === 'string') {
      throw new Error('Expected an IPv4 test listener address.')
    }
    const healthUrl = `http://127.0.0.1:${address.port}`

    try {
      const result = await runCli(
        [
          runtimeReadinessScript,
          '--frontend-env',
          frontendEnv,
          '--server-env',
          serverEnv,
          '--health-url',
          healthUrl,
          '--json',
        ],
      )

      expect(result.status).toBe(1)
      expect(result.stderr).toBe('')

      const report = JSON.parse(result.stdout)
      expect(report.ok).toBe(false)
      expect(report.failures.some((item) => item.includes('Live auth health check failed: Live auth health endpoint returned HTML instead of JSON.'))).toBe(true)
      expect(report.failures.some((item) => item.includes('placeholder rollout page'))).toBe(true)
      expect(report.failures.some((item) => item.includes('Live release manifest check failed: Live release manifest endpoint returned HTML instead of JSON.'))).toBe(true)
      expect(report.failures.some((item) => item.includes('Live website root still serves the placeholder rollout page'))).toBe(true)
    } finally {
      await new Promise((resolve, reject) => {
        server.close((error) => {
          if (error) {
            reject(error)
            return
          }
          resolve()
        })
      })
      fs.rmSync(tempDir, { recursive: true, force: true })
    }
  })
})
