import { describe, expect, it } from 'vitest'
import type { Request } from 'express'

import {
  TEST_SESSION_HEADER,
  createSessionLikeFromTestPayload,
  createSignedTestSessionValue,
  readSignedTestSessionFromRequest,
  verifySignedTestSessionValue,
} from '../test-session'

function createRequestWithHeader(value: string): Request {
  return {
    header(name: string) {
      return name.toLowerCase() === TEST_SESSION_HEADER ? value : undefined
    },
  } as Request
}

describe('test-session helpers', () => {
  it('signs and verifies bounded testing-session payloads', () => {
    const signedValue = createSignedTestSessionValue({
      userId: 'user-1',
      email: 'operator@hypertwist.app',
      plan: 'operator',
      role: 'operator',
      name: 'Operator',
      authMethod: 'email',
    }, 'secret')

    expect(verifySignedTestSessionValue({
      headerValue: signedValue,
      secret: 'secret',
    })).toEqual({
      userId: 'user-1',
      email: 'operator@hypertwist.app',
      plan: 'operator',
      role: 'operator',
      name: 'Operator',
      authMethod: 'email',
    })

    expect(readSignedTestSessionFromRequest(createRequestWithHeader(signedValue), 'secret')).toEqual({
      userId: 'user-1',
      email: 'operator@hypertwist.app',
      plan: 'operator',
      role: 'operator',
      name: 'Operator',
      authMethod: 'email',
    })
  })

  it('rejects malformed or mismatched testing-session headers', () => {
    const signedValue = createSignedTestSessionValue({
      userId: 'user-2',
      email: 'operator@hypertwist.app',
    }, 'secret')

    expect(verifySignedTestSessionValue({
      headerValue: `${signedValue}tampered`,
      secret: 'secret',
    })).toBeNull()
    expect(verifySignedTestSessionValue({
      headerValue: signedValue,
      secret: 'wrong-secret',
    })).toBeNull()
    expect(verifySignedTestSessionValue({
      headerValue: 'not-a-valid-token',
      secret: 'secret',
    })).toBeNull()
  })

  it('creates a session-like adapter that can merge payload updates', async () => {
    const session = createSessionLikeFromTestPayload({
      userId: 'user-3',
      email: 'operator@hypertwist.app',
      plan: 'free',
      role: 'operator',
    })

    expect(session.getUserId()).toBe('user-3')
    expect(session.getAccessTokenPayload()).toMatchObject({
      email: 'operator@hypertwist.app',
      plan: 'free',
      role: 'operator',
    })

    await session.mergeIntoAccessTokenPayload({
      plan: 'operator',
      role: 'admin',
    })

    expect(session.getAccessTokenPayload()).toMatchObject({
      email: 'operator@hypertwist.app',
      plan: 'operator',
      role: 'admin',
    })
  })
})
