import request from 'supertest'
import { app } from '../src/index.js'
import { User } from '../src/models/index.js'

describe('Auth Routes', () => {
  beforeEach(async () => {
    await User.destroy({ where: {}, force: true })
  })

  describe('POST /api/auth/register', () => {
    it('should register a new user successfully', async () => {
      const res = await request(app)
        .post('/api/auth/register')
        .send({
          name: 'John Doe',
          email: 'john@example.com',
          password: 'password123',
          role: 'user'
        })

      expect(res.statusCode).toBe(201)
      expect(res.body).toHaveProperty('user')
      expect(res.body.user).toHaveProperty('id')
      expect(res.body.user.email).toBe('john@example.com')
      expect(res.body.user.name).toBe('John Doe')
      expect(res.body.user.role).toBe('user')
    })

    it('should return 400 for missing required fields', async () => {
      const res = await request(app)
        .post('/api/auth/register')
        .send({})

      expect(res.statusCode).toBe(400)
      expect(res.body).toHaveProperty('errors')
    })

    it('should return 400 for duplicate email', async () => {
      await request(app)
        .post('/api/auth/register')
        .send({
          name: 'John Doe',
          email: 'john@example.com',
          password: 'password123',
          role: 'user'
        })

      const res = await request(app)
        .post('/api/auth/register')
        .send({
          name: 'Jane Doe',
          email: 'john@example.com',
          password: 'password456',
          role: 'user'
        })

      expect(res.statusCode).toBe(400)
      expect(res.body.error).toBe('Email already registered')
    })

    it('should return 400 for invalid email format', async () => {
      const res = await request(app)
        .post('/api/auth/register')
        .send({
          name: 'John Doe',
          email: 'invalid-email',
          password: 'password123',
          role: 'user'
        })

      expect(res.statusCode).toBe(400)
    })

    it('should return 400 for short password', async () => {
      const res = await request(app)
        .post('/api/auth/register')
        .send({
          name: 'John Doe',
          email: 'john@example.com',
          password: '123',
          role: 'user'
        })

      expect(res.statusCode).toBe(400)
    })

    it('should set httpOnly cookie on successful registration', async () => {
      const res = await request(app)
        .post('/api/auth/register')
        .send({
          name: 'John Doe',
          email: 'john@example.com',
          password: 'password123',
          role: 'user'
        })

      expect(res.headers['set-cookie']).toBeDefined()
      const cookie = res.headers['set-cookie'][0]
      expect(cookie).toContain('token=')
      expect(cookie).toContain('HttpOnly')
    })
  })

  describe('POST /api/auth/login', () => {
    beforeEach(async () => {
      await request(app)
        .post('/api/auth/register')
        .send({
          name: 'John Doe',
          email: 'john@example.com',
          password: 'password123',
          role: 'user'
        })
    })

    it('should login successfully with valid credentials', async () => {
      const res = await request(app)
        .post('/api/auth/login')
        .send({
          email: 'john@example.com',
          password: 'password123'
        })

      expect(res.statusCode).toBe(200)
      expect(res.body).toHaveProperty('user')
      expect(res.body.user.email).toBe('john@example.com')
    })

    it('should return 401 for invalid password', async () => {
      const res = await request(app)
        .post('/api/auth/login')
        .send({
          email: 'john@example.com',
          password: 'wrongpassword'
        })

      expect(res.statusCode).toBe(401)
      expect(res.body.error).toBe('Invalid credentials')
    })

    it('should return 401 for non-existent user', async () => {
      const res = await request(app)
        .post('/api/auth/login')
        .send({
          email: 'nonexistent@example.com',
          password: 'password123'
        })

      expect(res.statusCode).toBe(401)
      expect(res.body.error).toBe('Invalid credentials')
    })

    it('should return 400 for missing fields', async () => {
      const res = await request(app)
        .post('/api/auth/login')
        .send({})

      expect(res.statusCode).toBe(400)
    })

    it('should set httpOnly cookie on successful login', async () => {
      const res = await request(app)
        .post('/api/auth/login')
        .send({
          email: 'john@example.com',
          password: 'password123'
        })

      expect(res.headers['set-cookie']).toBeDefined()
      const cookie = res.headers['set-cookie'][0]
      expect(cookie).toContain('token=')
      expect(cookie).toContain('HttpOnly')
    })
  })

  describe('POST /api/auth/logout', () => {
    it('should logout successfully', async () => {
      const res = await request(app)
        .post('/api/auth/logout')

      expect(res.statusCode).toBe(200)
      expect(res.body.message).toBe('Logged out')
    })

    it('should clear the token cookie', async () => {
      const res = await request(app)
        .post('/api/auth/logout')

      expect(res.headers['set-cookie']).toBeDefined()
      const cookie = res.headers['set-cookie'][0]
      expect(cookie).toContain('token=')
      // Cookie is cleared with Expires in the past
      expect(cookie).toMatch(/Expires=|Max-Age=0/)
    })
  })

  describe('GET /api/auth/me', () => {
    it('should return 401 without authentication', async () => {
      const res = await request(app)
        .get('/api/auth/me')

      expect(res.statusCode).toBe(401)
    })
  })
})

// afterAll handled by jest config forceExit