import test from 'node:test'
import assert from 'node:assert/strict'

import {
  isReleaseExcluded,
  parseNodeMajor,
  parseWranglerD1DatabaseId,
  parseWranglerWorkerUrl,
  patchWranglerToml,
  renderWorkerEnv,
  cloudflareSeedCommandArgs,
  sanitizeD1SeedSql,
  formatReleaseStamp,
} from './student-release-utils.mjs'

test('parseNodeMajor accepts normal Node version strings', () => {
  assert.equal(parseNodeMajor('v24.14.1'), 24)
  assert.equal(parseNodeMajor('22.11.0'), 22)
  assert.equal(parseNodeMajor('bad-version'), 0)
})

test('formatReleaseStamp uses the classroom local date instead of UTC', () => {
  assert.equal(
    formatReleaseStamp(new Date('2026-07-19T17:24:25.000Z'), 'Asia/Shanghai'),
    '20260720-012425',
  )
})

test('isReleaseExcluded removes generated dependencies, local data, secrets, and release output', () => {
  const excluded = [
    'node_modules/react/index.js',
    '.worktrees/local-bridge-qoder-cloud/node_modules/workerd/bin/workerd',
    'cf-worker/node_modules/hono/dist/index.js',
    'dist/assets/index.js',
    '.env',
    '.env.local',
    'cf-worker/.env',
    'cf-worker/data/aipro.db',
    'cf-worker/uploads/pkg.zip',
    'deploy/ssl/zhenyuskill.com.key',
    'deploy/cert.zip',
    'release/aipros-lite.zip',
    '.wrangler/state/v3/cache',
    'cf-worker/.wrangler/tmp',
  ]
  for (const relPath of excluded) {
    assert.equal(isReleaseExcluded(relPath), true, `${relPath} should be excluded`)
  }

  const included = [
    'README.md',
    'README-STUDENT.md',
    'AI-CODING-PROMPT.md',
    'package.json',
    'cf-worker/package.json',
    'cf-worker/migrations/0001_init.sql',
    'cf-worker/migrations/0017_local_runtime_student_presets.sql',
    'cf-worker/migrations/0019_direct_skill_create.sql',
    'cf-worker/migrations/0020_unified_runtime_streaming.sql',
    'cf-worker/seed/categories.sql',
    'src/App.jsx',
    'scripts/runtime-presets.mjs',
    'scripts/aipros-auto-start.mjs',
    'scripts/aipros-runtime-setup.mjs',
    'scripts/apply-local-runtime-patch.mjs',
  ]
  for (const relPath of included) {
    assert.equal(isReleaseExcluded(relPath), false, `${relPath} should be included`)
  }
})

test('parseWranglerD1DatabaseId reads the database id from wrangler output', () => {
  const output = `
[[d1_databases]]
binding = "DB"
database_name = "aipro-skill-db"
database_id = "12345678-abcd-4000-8000-123456789abc"
`
  assert.equal(parseWranglerD1DatabaseId(output), '12345678-abcd-4000-8000-123456789abc')
})

test('parseWranglerWorkerUrl reads workers.dev urls from deploy output', () => {
  const output = 'Uploaded aipros-lite-api (4.20 sec)\\nhttps://aipros-lite-api.example.workers.dev'
  assert.equal(parseWranglerWorkerUrl(output), 'https://aipros-lite-api.example.workers.dev')
})

test('patchWranglerToml updates Cloudflare ids and allowed origins', () => {
  const toml = `
name = "aipros-lite-api"
database_id = "00000000-0000-0000-0000-000000000000"
ALLOW_ORIGINS = "https://your-pages-domain.pages.dev,http://localhost:5180"
`
  const patched = patchWranglerToml(toml, {
    databaseId: '12345678-abcd-4000-8000-123456789abc',
    allowOrigins: 'https://aipros-lite.pages.dev,http://localhost:5180',
  })
  assert.match(patched, /database_id = "12345678-abcd-4000-8000-123456789abc"/)
  assert.match(patched, /ALLOW_ORIGINS = "https:\/\/aipros-lite\.pages\.dev,http:\/\/localhost:5180"/)
})

test('renderWorkerEnv points the single-port local app at the built frontend and sqlite database', () => {
  const env = renderWorkerEnv({
    port: 4010,
    rootDir: '/tmp/aipros',
  })
  assert.match(env, /PORT=4010/)
  assert.match(env, /DB_PATH=\/tmp\/aipros\/cf-worker\/data\/aipro\.db/)
  assert.match(env, /DIST_DIR=\/tmp\/aipros\/dist/)
  assert.match(env, /ALLOW_ORIGINS=http:\/\/localhost:4010,http:\/\/127\.0\.0\.1:4010/)
})

test('cloudflareSeedCommandArgs seeds the remote D1 categories table from the bundled sql file', () => {
  assert.deepEqual(cloudflareSeedCommandArgs('demo-db'), [
    'wrangler',
    'd1',
    'execute',
    'demo-db',
    '--remote',
    '--file=./.tmp/categories.cloudflare.sql',
  ])
})

test('sanitizeD1SeedSql removes local sqlite transaction wrappers for remote D1 execute', () => {
  const sql = `
-- comment
BEGIN;
INSERT OR REPLACE INTO categories (id, name) VALUES ('a', 'A');
COMMIT;
`
  const sanitized = sanitizeD1SeedSql(sql)
  assert.doesNotMatch(sanitized, /^BEGIN;$/m)
  assert.doesNotMatch(sanitized, /^COMMIT;$/m)
  assert.match(sanitized, /INSERT OR REPLACE INTO categories/)
})
