import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'

vi.mock('../../../server/models/member.js', () => ({
  default: { findOne: vi.fn(), create: vi.fn(), findOneAndUpdate: vi.fn() }
}))

vi.mock('../../../server/utils/mongoose.js', () => ({
  connectDB: vi.fn()
}))

vi.mock('jsonwebtoken', () => ({
  default: { sign: vi.fn().mockReturnValue('mock-token') }
}))

import Member from '../../../server/models/member.js'
import testLoginHandler from '../../../server/api/dev/test-login.get.js'
import memberLoginHandler from '../../../server/api/dev/member-login.get.js'
import { createMockEvent } from '../helpers/createMockEvent.js'

const mockMember = {
  _id: 'member-123',
  email: 'test-admin@ghostguild.dev',
  name: 'Test Admin',
  circle: 'founder',
  role: 'admin',
  status: 'active'
}

describe('dev endpoints', () => {
  let originalNodeEnv

  beforeEach(() => {
    originalNodeEnv = process.env.NODE_ENV
    process.env.NODE_ENV = 'development'
    vi.clearAllMocks()
  })

  afterEach(() => {
    process.env.NODE_ENV = originalNodeEnv
  })

  // ── Source inspection ──────────────────────────────────────────

  describe('source inspection', () => {
    const devDir = resolve(import.meta.dirname, '../../../server/api/dev')

    it('test-login.get.js first conditional is NODE_ENV production check', () => {
      const source = readFileSync(resolve(devDir, 'test-login.get.js'), 'utf-8')
      const handlerBody = source.slice(source.indexOf('defineEventHandler'))
      const firstIf = handlerBody.match(/if\s*\([\s\S]*?\)\s*\{/)?.[0]
      expect(firstIf).toContain('process.env.NODE_ENV === "production"')
    })

    it('member-login.get.js first conditional is NODE_ENV production check', () => {
      const source = readFileSync(resolve(devDir, 'member-login.get.js'), 'utf-8')
      const handlerBody = source.slice(source.indexOf('defineEventHandler'))
      const firstIf = handlerBody.match(/if\s*\([\s\S]*?\)\s*\{/)?.[0]
      expect(firstIf).toContain('process.env.NODE_ENV === "production"')
    })
  })

  // ── test-login.get.js ──────────────────────────────────────────

  describe('test-login.get.js', () => {
    it('returns 404 in production', async () => {
      process.env.NODE_ENV = 'production'
      const event = createMockEvent({ method: 'GET', path: '/api/dev/test-login' })

      await expect(testLoginHandler(event)).rejects.toMatchObject({
        statusCode: 404
      })
    })

    it('creates admin user when none exists', async () => {
      Member.findOneAndUpdate.mockResolvedValue(mockMember)

      const event = createMockEvent({ method: 'GET', path: '/api/dev/test-login' })
      await testLoginHandler(event)

      expect(Member.findOneAndUpdate).toHaveBeenCalledWith(
        { email: 'test-admin@ghostguild.dev' },
        expect.objectContaining({
          $setOnInsert: expect.objectContaining({
            role: 'admin',
            circle: 'founder'
          })
        }),
        { upsert: true, new: true }
      )
    })

    it('uses existing admin when found', async () => {
      Member.findOneAndUpdate.mockResolvedValue(mockMember)

      const event = createMockEvent({ method: 'GET', path: '/api/dev/test-login' })
      await testLoginHandler(event)

      expect(Member.findOneAndUpdate).toHaveBeenCalledWith(
        { email: 'test-admin@ghostguild.dev' },
        expect.any(Object),
        { upsert: true, new: true }
      )
    })

    it('sets auth cookie', async () => {
      Member.findOneAndUpdate.mockResolvedValue(mockMember)

      const event = createMockEvent({ method: 'GET', path: '/api/dev/test-login' })
      await testLoginHandler(event)

      const cookieHeader = event._testSetHeaders['set-cookie']
      expect(cookieHeader).toBeDefined()
      expect(cookieHeader).toContain('auth-token=mock-token')
    })
  })

  // ── member-login.get.js ────────────────────────────────────────

  describe('member-login.get.js', () => {
    it('returns 404 in production', async () => {
      process.env.NODE_ENV = 'production'
      const event = createMockEvent({ method: 'GET', path: '/api/dev/member-login' })

      await expect(memberLoginHandler(event)).rejects.toMatchObject({
        statusCode: 404
      })
    })

    it('returns 400 when email query param is missing', async () => {
      const event = createMockEvent({ method: 'GET', path: '/api/dev/member-login' })

      await expect(memberLoginHandler(event)).rejects.toMatchObject({
        statusCode: 400
      })
    })

    it('returns 404 when member not found', async () => {
      Member.findOne.mockResolvedValue(null)

      const event = createMockEvent({
        method: 'GET',
        path: '/api/dev/member-login?email=nobody@example.com'
      })

      await expect(memberLoginHandler(event)).rejects.toMatchObject({
        statusCode: 404
      })
    })

    it('sets auth cookie for found member', async () => {
      const foundMember = {
        _id: 'member-456',
        email: 'test@example.com',
        name: 'Test User',
        status: 'active'
      }
      Member.findOne.mockResolvedValue(foundMember)

      const event = createMockEvent({
        method: 'GET',
        path: '/api/dev/member-login?email=test@example.com'
      })
      await memberLoginHandler(event)

      const cookieHeader = event._testSetHeaders['set-cookie']
      expect(cookieHeader).toBeDefined()
      expect(cookieHeader).toContain('auth-token=mock-token')
    })
  })
})
