const assert = require('assert')
const fs = require('fs')
const os = require('os')
const path = require('path')
const test = require('node:test')

const {
  getCmsDependenciesBoilerplate,
  getComponentsBarrelBoilerplate,
  sitePathMustBeDirectory,
  writeCmsDependenciesBoilerplate,
  writeCmsDependenciesBoilerplateToFilePath,
  writeComponentsBarrelBoilerplate,
} = require('../src/lib/cms-dependencies-boilerplate')

test('boilerplate includes React, Next, and @/ example comment', () => {
  const s = getCmsDependenciesBoilerplate()
  assert.match(s, /'use client'/)
  assert.match(s, /import \* as React from 'react'/)
  assert.match(s, /from 'next\/image'/)
  assert.match(s, /@\/components\/Example/)
  assert.match(s, /const cmsDependencies/)
  assert.match(s, /getRemoteProps/)
  assert.match(s, /window\.React = React/)
})

test('writeCmsDependenciesBoilerplate creates file and skips if present', () => {
  const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'bild-cmsdeps-'))
  const rel = 'src/cmsDependencies.ts'
  const abs = path.join(dir, rel)

  const first = writeCmsDependenciesBoilerplate(dir, rel)
  assert.strictEqual(first.ok, true)
  assert.strictEqual(first.skipped, false)
  assert.strictEqual(fs.readFileSync(abs, 'utf8'), getCmsDependenciesBoilerplate())

  const second = writeCmsDependenciesBoilerplate(dir, rel)
  assert.strictEqual(second.ok, true)
  assert.strictEqual(second.skipped, true)
})

test('writeCmsDependenciesBoilerplate fails when site path missing', () => {
  const dir = path.join(os.tmpdir(), 'bild-nonexistent-' + Date.now())
  const r = writeCmsDependenciesBoilerplate(dir, 'src/cmsDependencies.ts')
  assert.strictEqual(r.ok, false)
  assert.ok(r.reason)
})

test('sitePathMustBeDirectory rejects a file (e.g. cmsDependencies path as sitePath)', () => {
  const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'bild-site-'))
  const file = path.join(dir, 'cmsDependencies.tsx')
  fs.writeFileSync(file, 'x', 'utf8')
  const r = sitePathMustBeDirectory(file)
  assert.strictEqual(r.ok, false)
  assert.match(r.reason, /directory/i)
  assert.match(r.reason, /sitePath/)
})

test('writeComponentsBarrelBoilerplate fails when sitePath is a file not a project root', () => {
  const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'bild-site-'))
  const file = path.join(dir, 'utils', 'cmsDependencies.tsx')
  fs.mkdirSync(path.dirname(file), { recursive: true })
  fs.writeFileSync(file, 'x', 'utf8')
  const r = writeComponentsBarrelBoilerplate(file, 'src/app/components/Components.tsx')
  assert.strictEqual(r.ok, false)
  assert.match(r.reason, /directory/i)
})

test('writeCmsDependenciesBoilerplateToFilePath and --force on existing', () => {
  const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'bild-cmsdeps-'))
  const custom = path.join(dir, 'lib', 'deps.ts')
  const first = writeCmsDependenciesBoilerplateToFilePath(custom)
  assert.strictEqual(first.ok, true)
  assert.strictEqual(first.skipped, false)
  const second = writeCmsDependenciesBoilerplateToFilePath(custom)
  assert.strictEqual(second.skipped, true)
  fs.writeFileSync(custom, 'touched', 'utf8')
  const third = writeCmsDependenciesBoilerplateToFilePath(custom, { force: true })
  assert.strictEqual(third.skipped, false)
  assert.match(fs.readFileSync(custom, 'utf8'), /const cmsDependencies/)
})

test('writeCmsDependenciesBoilerplate with force overwrites', () => {
  const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'bild-cmsdeps-'))
  const rel = 'src/cmsDependencies.ts'
  const abs = path.join(dir, rel)
  fs.mkdirSync(path.dirname(abs), { recursive: true })
  fs.writeFileSync(abs, 'old', 'utf8')
  const r = writeCmsDependenciesBoilerplate(dir, rel, { force: true })
  assert.strictEqual(r.skipped, false)
  assert.match(fs.readFileSync(abs, 'utf8'), /const cmsDependencies/)
})

test('getCmsDependenciesBoilerplate withComponents adds @components and namespace import', () => {
  const s = getCmsDependenciesBoilerplate({ withComponents: true })
  assert.match(s, /import \* as Components from '@\/app\/components\/Components'/)
  assert.match(s, /'@components':\s*{\s*module: Components/)
  assert.match(s, /'@\/app\/components\/Components':\s*{\s*module: Components/)
})

test('getComponentsBarrelBoilerplate documents barrel and placeholder export', () => {
  const s = getComponentsBarrelBoilerplate()
  assert.match(s, /'use client'/)
  assert.match(s, /Shared UI barrel/)
  assert.match(s, /\/\/ export/)
})

test('new cms file infers withComponents when barrel file already present', () => {
  const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'bild-cms-infer-'))
  const relBarrel = 'src/app/components/Components.tsx'
  const barrel = path.join(dir, relBarrel)
  fs.mkdirSync(path.dirname(barrel), { recursive: true })
  fs.writeFileSync(barrel, 'export const X = 1\n', 'utf8')
  const r = writeCmsDependenciesBoilerplate(dir, 'src/cmsDependencies.ts', {})
  assert.strictEqual(r.withComponents, true)
  const cms = fs.readFileSync(path.join(dir, 'src/cmsDependencies.ts'), 'utf8')
  assert.match(cms, /'@components'/)
})
