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

import {
  timingSafeEqual as hostTimingSafeEqual,
  encryptSecret as hostEncryptSecret,
  decryptSecret as hostDecryptSecret,
} from '../../../../../../packages/auth/src/crypto'
import {
  generateOpaqueToken as hostGenerateOpaqueToken,
  hashToken as hostHashToken,
  verifyToken as hostVerifyToken,
} from '../../../../../../packages/auth/src/tokens'
import {
  decryptSecret as platformDecryptSecret,
  encryptSecret as platformEncryptSecret,
  timingSafeEqual as platformTimingSafeEqual,
} from '@platform-modules/util/crypto'
import {
  generateOpaqueToken as platformGenerateOpaqueToken,
  hashToken as platformHashToken,
  verifyToken as platformVerifyToken,
} from '@platform-modules/util/tokens'
import {
  decryptSecret,
  encryptSecret,
  generateOpaqueToken,
  hashToken,
  timingSafeEqual,
  verifyToken,
} from '../util'

const AES_KEY_B64 = 'MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY='

describe('platform util parity', () => {
  it('matches timing-safe comparison verdicts on equal, unequal, and length-mismatch inputs', () => {
    const cases = [
      ['match', 'match'],
      ['match', 'mismatch'],
      ['short', 'longer'],
      ['', ''],
    ] as const

    for (const [left, right] of cases) {
      expect(timingSafeEqual(left, right)).toBe(hostTimingSafeEqual(left, right))
      expect(platformTimingSafeEqual(left, right)).toBe(hostTimingSafeEqual(left, right))
    }
  })

  it('hashes and verifies tokens exactly like the host implementation', async () => {
    const token = 'plain-token-value'

    const hostHash = await hostHashToken(token)
    const platformHash = await hashToken(token)

    expect(platformHash).toBe(hostHash)
    expect(await platformHashToken(token)).toBe(hostHash)
    expect(await verifyToken(token, hostHash)).toBe(await hostVerifyToken(token, hostHash))
    expect(await platformVerifyToken(token, hostHash)).toBe(await hostVerifyToken(token, hostHash))
    expect(await verifyToken('different-token', hostHash)).toBe(false)
  })

  it('generates opaque tokens with the same shape as the host implementation', () => {
    const hostToken = hostGenerateOpaqueToken(32)
    const platformToken = generateOpaqueToken(32)
    const directPlatformToken = platformGenerateOpaqueToken(32)

    for (const candidate of [hostToken, platformToken, directPlatformToken]) {
      expect(candidate).toMatch(/^[A-Za-z0-9_-]+$/)
      expect(candidate).toHaveLength(43)
    }
  })

  it('round-trips encrypted secrets across host and platform implementations', async () => {
    const plaintext = 'super-secret-value'

    const hostCipher = await hostEncryptSecret(plaintext, AES_KEY_B64)
    const platformCipher = await encryptSecret(plaintext, AES_KEY_B64)

    expect(await decryptSecret(hostCipher, AES_KEY_B64)).toBe(plaintext)
    expect(await platformDecryptSecret(hostCipher, AES_KEY_B64)).toBe(plaintext)
    expect(await hostDecryptSecret(platformCipher, AES_KEY_B64)).toBe(plaintext)
    expect(await decryptSecret(platformCipher, AES_KEY_B64)).toBe(plaintext)
    expect(await platformDecryptSecret(platformCipher, AES_KEY_B64)).toBe(plaintext)
    expect(await encryptSecret(plaintext, AES_KEY_B64)).not.toBe(hostCipher)
    expect(await platformEncryptSecret(plaintext, AES_KEY_B64)).not.toBe(platformCipher)
  })
})
