/**
 * Regression for #37718: macOS microphone entitlement must be inherited.
 *
 * Hermes Desktop signs with ``hardenedRuntime: true`` and points
 * electron-builder at two entitlement files (see ``apps/desktop/package.json``):
 *
 * - ``entitlements`` → ``electron/entitlements.mac.plist`` (the main app), and
 * - ``entitlementsInherit`` → ``electron/entitlements.mac.inherit.plist``
 *   (the Electron Helper / Setup processes).
 *
 * Under the hardened runtime, the process that actually opens the microphone
 * is a Helper, which inherits the *inherit* plist.
 * ``com.apple.security.device.audio-input`` lived only in the main plist, so
 * macOS' TCC layer refused the microphone with:
 *
 *     Prompting policy for hardened runtime; service: kTCCServiceMicrophone
 *     requires entitlement com.apple.security.device.audio-input but it is missing
 *
 * and never showed the permission prompt. These tests pin that every device
 * entitlement granted to the main app is also granted to the inherited helpers.
 *
 * (Ported from tests/test_desktop_mac_entitlements.py — plist assertions about
 * apps/desktop/electron/*.plist belong in the JS lane because the CI change
 * classifier skips the Python suite on apps/-only PRs.)
 */

import assert from 'node:assert/strict'
import fs from 'node:fs'
import path from 'node:path'

import * as plist from 'plist'
import { test } from 'vitest'

const REPO_ROOT = path.resolve(__dirname, '..')
const ELECTRON_DIR = path.join(REPO_ROOT, 'apps', 'desktop', 'electron')
const MAIN_PLIST = path.join(ELECTRON_DIR, 'entitlements.mac.plist')
const INHERIT_PLIST = path.join(ELECTRON_DIR, 'entitlements.mac.inherit.plist')
const BOOTSTRAP_TAURI_DIR = path.join(REPO_ROOT, 'apps', 'bootstrap-installer', 'src-tauri')
const BOOTSTRAP_TAURI_CONFIG = path.join(BOOTSTRAP_TAURI_DIR, 'tauri.conf.json')
const BOOTSTRAP_ENTITLEMENTS = path.join(BOOTSTRAP_TAURI_DIR, 'entitlements.plist')
const BOOTSTRAP_INFO_PLIST = path.join(BOOTSTRAP_TAURI_DIR, 'Info.plist')

const DEVICE_PREFIX = 'com.apple.security.device.'

function loadEntitlements(plistPath: string): Record<string, unknown> {
  assert.ok(fs.existsSync(plistPath), `missing entitlements file: ${plistPath}`)
  const data = plist.parse(fs.readFileSync(plistPath, 'utf-8'))
  assert.ok(
    typeof data === 'object' && data !== null && !Array.isArray(data),
    `${path.basename(plistPath)} should parse to a dict`
  )

  return data as Record<string, unknown>
}

test('inherit plist grants microphone (regression #37718)', () => {
  const inherit = loadEntitlements(INHERIT_PLIST)
  assert.equal(
    inherit['com.apple.security.device.audio-input'],
    true,
    'entitlements.mac.inherit.plist must grant ' +
      '`com.apple.security.device.audio-input`; without it the ' +
      'hardened-runtime Helper process is denied the microphone and no ' +
      'TCC prompt appears (#37718).'
  )
})

test('every device.* entitlement on the main app is also inherited', () => {
  const main = loadEntitlements(MAIN_PLIST)
  const inherit = loadEntitlements(INHERIT_PLIST)

  const missing = Object.entries(main)
    .filter(([key, val]) => key.startsWith(DEVICE_PREFIX) && val === true)
    .map(([key]) => key)
    .filter((key) => inherit[key] !== true)

  assert.deepEqual(
    missing,
    [],
    'Device entitlements present in entitlements.mac.plist but missing from ' +
      `entitlements.mac.inherit.plist: ${JSON.stringify(missing)}. ` +
      'Helper/Setup processes inherit the latter under hardenedRuntime, so ' +
      'any device access the app needs must be listed in both (#37718).'
  )
})

for (const plist of [MAIN_PLIST, INHERIT_PLIST]) {
  test(`${path.basename(plist)} is a well-formed non-empty entitlement dict`, () => {
    const data = loadEntitlements(plist)
    assert.ok(
      Object.keys(data).length > 0,
      `${path.basename(plist)} should be a non-empty dict`
    )
  })
}

test('bootstrap installer carries microphone entitlement for launcher attribution', () => {
  const config = JSON.parse(fs.readFileSync(BOOTSTRAP_TAURI_CONFIG, 'utf-8'))
  assert.equal(
    config.bundle?.macOS?.entitlements,
    'entitlements.plist',
    'the macOS bootstrap installer must sign with its entitlements.plist. ' +
      'When /Applications/Hermes.app is the setup launcher, macOS TCC treats ' +
      'com.nousresearch.hermes.setup as the responsible process for the desktop ' +
      'app it opens; without audio-input on the setup app, microphone access is ' +
      'denied before a permission prompt can appear.'
  )

  const entitlements = loadEntitlements(BOOTSTRAP_ENTITLEMENTS)
  assert.equal(
    entitlements['com.apple.security.device.audio-input'],
    true,
    'bootstrap installer entitlements must grant audio-input because it is the ' +
      'TCC responsible process for the desktop app launched from the setup fast path'
  )
})

test('bootstrap installer Info.plist explains microphone usage', () => {
  const info = plist.parse(fs.readFileSync(BOOTSTRAP_INFO_PLIST, 'utf-8')) as Record<
    string,
    unknown
  >

  assert.equal(
    typeof info.NSMicrophoneUsageDescription,
    'string',
    'macOS requires NSMicrophoneUsageDescription before it can prompt for microphone access'
  )
  assert.match(
    info.NSMicrophoneUsageDescription as string,
    /microphone/i,
    'microphone usage description should be user-visible and specific'
  )
})
