import request from 'supertest'
import { prisma } from '../../lib/prisma'
import { createApp } from '../../app'
import {
  authHeader,
  createCompanyWithEmployee,
  createSubscriptionInvoice,
  signEmployeeToken,
} from '../helpers/fixtures'

const app = createApp()

function uniqueEmail(prefix: string) {
  return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}@test.com`
}

describe('Subscription webhooks — signature bypass fix (VF-02)', () => {
  describe('POST /api/v1/subscriptions/webhooks/amanpay', () => {
    it('returns 401 when AmanPay is not configured (env vars absent)', async () => {
      // In the test environment AMANPAY_MERCHANT_ID / SECRET_KEY are not set,
      // so isConfigured() returns false. The fix ensures this returns 401, not 200.
      const res = await request(app)
        .post('/api/v1/subscriptions/webhooks/amanpay')
        .send({ transaction_id: 'txn_fake_sub', status: 'PAID' })

      expect(res.status).toBe(401)
      expect(res.body.error).toBe('invalid_signature')
    })

    it('does not activate a subscription for an unconfigured-provider request', async () => {
      const { company } = await createCompanyWithEmployee({ role: 'OWNER' })
      const sub = await prisma.subscription.findUniqueOrThrow({ where: { companyId: company.id } })
      const invoice = await createSubscriptionInvoice(company.id, sub.id, {
        status: 'PENDING',
        amanpayTransactionId: `sub-txn-bypass-${Date.now()}`,
      })

      const res = await request(app)
        .post('/api/v1/subscriptions/webhooks/amanpay')
        .send({ transaction_id: (invoice as any).amanpayTransactionId, status: 'PAID' })

      expect(res.status).toBe(401)

      // Invoice must remain PENDING — the handler was not invoked
      const unchanged = await prisma.subscriptionInvoice.findUniqueOrThrow({ where: { id: invoice.id } })
      expect(unchanged.status).toBe('PENDING')
    })
  })

  describe('POST /api/v1/subscriptions/webhooks/paypal', () => {
    it('returns 401 when PayPal is not configured (env vars absent)', async () => {
      const res = await request(app)
        .post('/api/v1/subscriptions/webhooks/paypal')
        .send({ event_type: 'BILLING.SUBSCRIPTION.ACTIVATED', resource: { id: 'sub-fake' } })

      expect(res.status).toBe(401)
      expect(res.body.error).toBe('invalid_signature')
    })
  })
})

describe('Subscriptions API', () => {
  let companyId: string
  let subscriptionId: string
  let ownerToken: string
  let agentToken: string

  beforeAll(async () => {
    const { company, employee } = await createCompanyWithEmployee({ role: 'OWNER' })
    companyId = company.id
    ownerToken = signEmployeeToken(employee.id, companyId, 'OWNER')

    const subscription = await prisma.subscription.findUniqueOrThrow({ where: { companyId } })
    subscriptionId = subscription.id

    const agent = await prisma.employee.create({
      data: {
        companyId,
        clerkUserId: `clerk_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
        firstName: 'Agent',
        lastName:  'User',
        email:     uniqueEmail('sub-agent'),
        role:      'AGENT',
      },
    })
    agentToken = signEmployeeToken(agent.id, companyId, 'AGENT')
  })

  describe('Public endpoints', () => {
    it('returns subscription plans', async () => {
      const res = await request(app).get('/api/v1/subscriptions/plans')

      expect(res.status).toBe(200)
      expect(res.body.data).toHaveProperty('STARTER')
      expect(res.body.data).toHaveProperty('GROWTH')
    })

    it('returns provider availability', async () => {
      const res = await request(app).get('/api/v1/subscriptions/providers')

      expect(res.status).toBe(200)
      expect(typeof res.body.data.amanpay).toBe('boolean')
      expect(typeof res.body.data.paypal).toBe('boolean')
    })
  })

  describe('Authenticated endpoints', () => {
    it('returns the current subscription', async () => {
      const res = await request(app)
        .get('/api/v1/subscriptions/me')
        .set(authHeader(ownerToken))

      expect(res.status).toBe(200)
      expect(res.body.data.companyId).toBe(companyId)
      expect(res.body.data.id).toBe(subscriptionId)
    })

    it('returns company invoices', async () => {
      const invoice = await createSubscriptionInvoice(companyId, subscriptionId)

      const res = await request(app)
        .get('/api/v1/subscriptions/invoices')
        .set(authHeader(ownerToken))

      expect(res.status).toBe(200)
      expect(Array.isArray(res.body.data)).toBe(true)
      expect(res.body.data.some((item: any) => item.id === invoice.id)).toBe(true)
    })

    it('changes the subscription plan for OWNER', async () => {
      const res = await request(app)
        .post('/api/v1/subscriptions/change-plan')
        .set(authHeader(ownerToken))
        .send({
          plan:          'GROWTH',
          billingPeriod: 'ANNUAL',
          currency:      'EUR',
        })

      expect(res.status).toBe(200)
      expect(res.body.data.plan).toBe('GROWTH')
      expect(res.body.data.billingPeriod).toBe('ANNUAL')
      expect(res.body.data.currency).toBe('EUR')
    })

    it('returns 403 for AGENT on plan changes', async () => {
      const res = await request(app)
        .post('/api/v1/subscriptions/change-plan')
        .set(authHeader(agentToken))
        .send({
          plan:          'PRO',
          billingPeriod: 'MONTHLY',
          currency:      'MAD',
        })

      expect(res.status).toBe(403)
    })

    it('cancels and resumes at period end', async () => {
      const cancelRes = await request(app)
        .post('/api/v1/subscriptions/cancel')
        .set(authHeader(ownerToken))

      expect(cancelRes.status).toBe(200)
      expect(cancelRes.body.data.cancelAtPeriodEnd).toBe(true)

      const resumeRes = await request(app)
        .post('/api/v1/subscriptions/resume')
        .set(authHeader(ownerToken))

      expect(resumeRes.status).toBe(200)
      expect(resumeRes.body.data.cancelAtPeriodEnd).toBe(false)
    })
  })
})
