import fs from 'node:fs'
import os from 'node:os'
import path from 'node:path'
import { fileURLToPath } from 'node:url'

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

import {
  buildBundleValidationReport,
  buildFrontendEnvEntries,
  buildServerEnvEntries,
  loadBundleManifest,
  renderSameOriginBundle,
  writeSameOriginBundle,
} from './render-same-origin-bundle-lib.mjs'

const currentFile = fileURLToPath(import.meta.url)
const websiteRoot = path.resolve(path.dirname(currentFile), '..')
const launchBundleExamplePath = path.join(websiteRoot, 'deploy', 'hypertwist.same-origin.bundle.example.json')
const previewBundleExamplePath = path.join(websiteRoot, 'deploy', 'hypertwist.same-origin.preview.bundle.example.json')

function createValidManifest() {
  return {
    deploymentTier: 'launch',
    checkoutRoot: '/srv/hypertwist/current',
    publicOrigin: 'https://hypertwist.app',
    supportEmail: 'hello@hypertwist.app',
    publicDocsUrl: 'https://docs.hypertwist.app',
    releaseNotesUrl: 'https://notes.hypertwist.app',
    correspondingSourceUrl: 'https://hypertwist.app/open-source/source.zip',
    openSourceRepoUrl: 'https://git.scriptoriumai.io/scriptoriumadmin/hypertwist',
    operatorCheckoutUrl: 'https://buy.paddle.com/operator',
    studioCheckoutUrl: 'https://buy.paddle.com/studio',
    windowsDownloadUrl: 'https://downloads.hypertwist.app/windows.exe',
    releaseManifestVersion: '1.0.0',
    releaseManifestChannel: 'candidate',
    windowsRelease: {
      buildId: 'win64-1000',
      sha256: 'abc123',
      fileSizeBytes: 123456789,
      publishedAt: '2026-06-22T00:00:00.000Z',
    },
    server: {
      paddleWebhookSecret: 'secret',
      paddleProductPlanMap: {
        prod_operator: 'operator',
      },
      paddlePricePlanMap: {
        pri_operator: 'operator',
      },
    },
  }
}

function createPreviewManifest() {
  return {
    deploymentTier: 'preview',
    checkoutRoot: '/srv/hypertwist/current',
    publicOrigin: 'https://hypertwist.app',
    supportEmail: 'hello@hypertwist.app',
    publicDocsUrl: 'https://hypertwist.app/docs',
    releaseNotesUrl: 'https://hypertwist.app/changelog',
    correspondingSourceUrl: 'https://git.scriptoriumai.io/scriptoriumadmin/hypertwist',
    openSourceRepoUrl: 'https://git.scriptoriumai.io/scriptoriumadmin/hypertwist',
    operatorCheckoutUrl: '',
    studioCheckoutUrl: '',
    windowsDownloadUrl: '',
    releaseManifestVersion: '',
    releaseManifestChannel: 'preview',
    windowsRelease: {
      buildId: '',
      sha256: '',
      fileSizeBytes: '',
      publishedAt: '',
    },
    server: {
      paddleWebhookSecret: '',
      paddleProductPlanMap: {},
      paddlePricePlanMap: {},
    },
  }
}

describe('buildFrontendEnvEntries', () => {
  it('derives consistent frontend env from the bundle manifest', () => {
    const env = buildFrontendEnvEntries(createValidManifest())

    expect(env.VITE_AUTH_API_BASE_URL).toBe('https://hypertwist.app')
    expect(env.VITE_WINDOWS_DOWNLOAD_URL).toBe('https://downloads.hypertwist.app/windows.exe')
    expect(env.VITE_PADDLE_CHECKOUT_URL_OPERATOR).toBe('https://buy.paddle.com/operator')
  })

  it('uses the manifest public origin when deriving auth env', () => {
    const env = buildFrontendEnvEntries({
      ...createValidManifest(),
      publicOrigin: 'https://preview.hypertwist.app',
    })

    expect(env.VITE_SUPERTOKENS_API_DOMAIN).toBe('https://preview.hypertwist.app')
    expect(env.VITE_SUPERTOKENS_WEBSITE_DOMAIN).toBe('https://preview.hypertwist.app')
    expect(env.VITE_AUTH_API_BASE_URL).toBe('https://preview.hypertwist.app')
  })

  it('enables ORCID in frontend env only when the server manifest carries a complete ORCID credential pair', () => {
    const env = buildFrontendEnvEntries({
      ...createValidManifest(),
      server: {
        ...createValidManifest().server,
        orcidClientId: 'orcid-client-id',
        orcidClientSecret: 'orcid-client-secret',
      },
    })

    expect(env.VITE_ORCID_OAUTH_ENABLED).toBe('true')
  })
})

describe('buildServerEnvEntries', () => {
  it('derives consistent server env from the bundle manifest', () => {
    const env = buildServerEnvEntries(createValidManifest())

    expect(env.PORT).toBe('3011')
    expect(env.API_DOMAIN).toBe('https://hypertwist.app')
    expect(env.WINDOWS_RELEASE_BUILD_ID).toBe('win64-1000')
    expect(env.PADDLE_PRODUCT_PLAN_MAP).toContain('prod_operator')
  })

  it('derives the public origin from server names when no explicit publicOrigin is set', () => {
    const env = buildServerEnvEntries({
      ...createValidManifest(),
      publicOrigin: '',
      serverNames: ['preview.hypertwist.app', 'hypertwist.app'],
    })

    expect(env.API_DOMAIN).toBe('https://preview.hypertwist.app')
    expect(env.WEBSITE_DOMAIN).toBe('https://preview.hypertwist.app')
  })

  it('carries ORCID server env through when the manifest declares the custom provider credentials', () => {
    const env = buildServerEnvEntries({
      ...createValidManifest(),
      server: {
        ...createValidManifest().server,
        orcidClientId: 'orcid-client-id',
        orcidClientSecret: 'orcid-client-secret',
        orcidIsSandbox: true,
      },
    })

    expect(env.ORCID_CLIENT_ID).toBe('orcid-client-id')
    expect(env.ORCID_CLIENT_SECRET).toBe('orcid-client-secret')
    expect(env.ORCID_IS_SANDBOX).toBe('true')
  })
})

describe('buildBundleValidationReport', () => {
  it('fails when placeholder values are still present in the manifest', () => {
    const report = buildBundleValidationReport({
      ...createValidManifest(),
      operatorCheckoutUrl: 'https://buy.paddle.com/replace-me-operator',
    })

    expect(report.ok).toBe(false)
    expect(report.failures).toContain('VITE_PADDLE_CHECKOUT_URL_OPERATOR still contains a placeholder value.')
  })

  it('accepts preview-tier bundle manifests with honest missing launch values', () => {
    const report = buildBundleValidationReport(createPreviewManifest())

    expect(report.ok).toBe(true)
    expect(report.failures).toEqual([])
    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('VITE_WINDOWS_DOWNLOAD_URL or WINDOWS_DOWNLOAD_URL is not set; Windows download will remain in preview posture until the release lane is configured.')
  })
})

describe('renderSameOriginBundle', () => {
  it('renders a runtime-ready bundle when required values are present', () => {
    const rendered = renderSameOriginBundle(createValidManifest())

    expect(rendered.validationReport.ok).toBe(true)
    expect(rendered.frontendEnvContent).toContain('VITE_PUBLIC_DEPLOYMENT_TIER=launch')
    expect(rendered.serverEnvContent).toContain('PORT=3011')
    expect(rendered.frontendEnvContent).toContain('VITE_WINDOWS_DOWNLOAD_URL=https://downloads.hypertwist.app/windows.exe')
    expect(rendered.serverEnvContent).toContain('RELEASE_MANIFEST_VERSION=1.0.0')
    expect(rendered.systemdContent).toContain('WorkingDirectory=/srv/hypertwist/current/website/server')
    expect(rendered.nginxContent).toContain('server_name hypertwist.app www.hypertwist.app;')
    expect(rendered.nginxContent).toContain('server 127.0.0.1:3011;')
  })

  it('renders a preview-tier bundle without checkout, download, or webhook values', () => {
    const rendered = renderSameOriginBundle(createPreviewManifest())

    expect(rendered.validationReport.ok).toBe(true)
    expect(rendered.frontendEnvContent).toContain('VITE_PUBLIC_DEPLOYMENT_TIER=preview')
    expect(rendered.frontendEnvContent).toContain('VITE_PADDLE_CHECKOUT_URL_OPERATOR=')
    expect(rendered.serverEnvContent).toContain('DEPLOYMENT_TIER=preview')
    expect(rendered.serverEnvContent).toContain('PADDLE_WEBHOOK_SECRET=')
  })

  it('keeps the checked-in launch example bundle intentionally non-ready until placeholders are replaced', () => {
    const { manifest } = loadBundleManifest(launchBundleExamplePath)

    expect(() => renderSameOriginBundle(manifest)).toThrow(/not runtime-ready/i)
  })

  it('renders the checked-in preview example bundle as an honest preview-tier deployment', () => {
    const { manifest } = loadBundleManifest(previewBundleExamplePath)
    const rendered = renderSameOriginBundle(manifest)

    expect(rendered.validationReport.ok).toBe(true)
    expect(rendered.validationReport.failures).toEqual([])
    expect(rendered.frontendEnv.VITE_PUBLIC_DEPLOYMENT_TIER).toBe('preview')
    expect(rendered.serverEnv.DEPLOYMENT_TIER).toBe('preview')
    expect(rendered.frontendEnv.VITE_MPL_SOURCE_URL).toBe('https://git.scriptoriumai.io/scriptoriumadmin/hypertwist')
    expect(rendered.serverEnv.PADDLE_WEBHOOK_SECRET).toBe('')
  })
})

describe('writeSameOriginBundle', () => {
  it('writes all bundle outputs to the chosen directory', () => {
    const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'hypertwist-bundle-render-'))

    try {
      const written = writeSameOriginBundle({
        manifest: createValidManifest(),
        outDir: tempDir,
      })

      expect(fs.readFileSync(written.frontendEnvPath, 'utf8')).toContain('VITE_SUPPORT_EMAIL=hello@hypertwist.app')
      expect(fs.readFileSync(written.serverEnvPath, 'utf8')).toContain('PADDLE_WEBHOOK_SECRET=secret')
      expect(fs.readFileSync(written.systemdPath, 'utf8')).toContain('EnvironmentFile=/srv/hypertwist/current/website/server/.env')
      expect(fs.readFileSync(written.nginxPath, 'utf8')).toContain('proxy_pass http://hypertwist_website_auth_server;')
      expect(JSON.parse(fs.readFileSync(written.summaryPath, 'utf8')).validationReport.ok).toBe(true)
    } finally {
      fs.rmSync(tempDir, { recursive: true, force: true })
    }
  })
})
