import { beforeEach, describe, expect, it, vi } from 'vitest'
import { createEvent, mockSuccessReadBody } from './setup'

vi.mock('../server/utils/auth.js', () => ({
  getUserFromToken: vi.fn(),
  readUsers: vi.fn(),
  writeUsers: vi.fn(),
  hasRole: vi.fn((user, role) => {
    if (!user) return false
    const userRoles = Array.isArray(user.roles) ? user.roles : (user.role ? [user.role] : [])
    return userRoles.includes(role)
  }),
  hasAnyRole: vi.fn((user, ...roles) => {
    if (!user) return false
    const userRoles = Array.isArray(user.roles) ? user.roles : (user.role ? [user.role] : [])
    return roles.some(r => userRoles.includes(r))
  }),
  migrateUserRoles: vi.fn((user) => {
    if (!user) return user
    if (Array.isArray(user.roles)) return user
    if (user.role) {
      user.roles = [user.role]
      delete user.role
    } else {
      user.roles = ['mitglied']
    }
    return user
  })
}))

vi.mock('nodemailer', () => {
  const sendMail = vi.fn().mockResolvedValue(true)
  const createTransport = vi.fn(() => ({ sendMail }))
  return {
    default: { createTransport },
    createTransport
  }
})

const authUtils = await import('../server/utils/auth.js')
const nodemailer = await import('nodemailer')

import usersListHandler from '../server/api/cms/users/list.get.js'
import usersApproveHandler from '../server/api/cms/users/approve.post.js'
import usersDeactivateHandler from '../server/api/cms/users/deactivate.post.js'
import usersRejectHandler from '../server/api/cms/users/reject.post.js'
import usersUpdateRoleHandler from '../server/api/cms/users/update-role.post.js'

describe('CMS User Management Endpoints', () => {
  beforeEach(() => {
    vi.clearAllMocks()
  })

  const adminEvent = () => {
    const event = createEvent({ cookies: { auth_token: 'token' } })
    authUtils.getUserFromToken.mockResolvedValue({ id: 'admin', roles: ['admin'] })
    authUtils.hasAnyRole.mockReturnValue(true)
    return event
  }

  describe('GET /api/cms/users/list', () => {
    it('verweigert Zugriff für Nicht-Admins', async () => {
      const event = createEvent({ cookies: { auth_token: 'token' } })
      authUtils.getUserFromToken.mockResolvedValue({ id: 'user', roles: ['mitglied'] })
      authUtils.hasAnyRole.mockReturnValue(false)

      await expect(usersListHandler(event)).rejects.toMatchObject({ statusCode: 403 })
    })

    it('liefert Benutzerliste ohne Passwörter', async () => {
      const event = adminEvent()
      authUtils.readUsers.mockResolvedValue([{ id: '1', email: 'a@b.de', name: 'Anna', roles: ['mitglied'], phone: '1', active: true, created: 'now', lastLogin: null, password: 'secret' }])
      authUtils.migrateUserRoles.mockImplementation((user) => {
        if (!user) return user
        if (Array.isArray(user.roles)) return user
        if (user.role) {
          user.roles = [user.role]
          delete user.role
        } else {
          user.roles = ['mitglied']
        }
        return user
      })

      const response = await usersListHandler(event)
      expect(response.users[0]).not.toHaveProperty('password')
      expect(response.users).toHaveLength(1)
    })
  })

  describe('POST /api/cms/users/approve', () => {
    it('erfordert administrative Rolle', async () => {
      const event = createEvent({ cookies: { auth_token: 'token' } })
      authUtils.getUserFromToken.mockResolvedValue({ id: 'user', roles: ['mitglied'] })
      authUtils.hasAnyRole.mockReturnValue(false)
      mockSuccessReadBody({ userId: '1' })

      await expect(usersApproveHandler(event)).rejects.toMatchObject({ statusCode: 403 })
    })

    it('meldet 404 bei unbekanntem Benutzer', async () => {
      const event = adminEvent()
      mockSuccessReadBody({ userId: '1' })
      authUtils.readUsers.mockResolvedValue([])

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

    it('aktiviert Benutzer und sendet Mail', async () => {
      const event = adminEvent()
      mockSuccessReadBody({ userId: '1', roles: ['vorstand'] })
      authUtils.readUsers.mockResolvedValue([{ id: '1', email: 'user@test.de', name: 'Udo', active: false }])
      authUtils.writeUsers.mockResolvedValue(true)
      // Setze SMTP-Credentials für Tests
      process.env.SMTP_USER = 'test@example.com'
      process.env.SMTP_PASS = 'test-password'

      const response = await usersApproveHandler(event)
      expect(response.success).toBe(true)
      expect(authUtils.writeUsers).toHaveBeenCalled()
      expect(nodemailer.default.createTransport).toHaveBeenCalled()
    })
  })

  describe('POST /api/cms/users/deactivate', () => {
    it('verhindert Selbst-Deaktivierung', async () => {
      const event = adminEvent()
      mockSuccessReadBody({ userId: 'admin' })
      await expect(usersDeactivateHandler(event)).rejects.toMatchObject({ statusCode: 400 })
    })

    it('deaktiviert Benutzer', async () => {
      const event = adminEvent()
      mockSuccessReadBody({ userId: '1' })
      authUtils.readUsers.mockResolvedValue([{ id: '1', active: true }])
      authUtils.writeUsers.mockResolvedValue(true)

      const response = await usersDeactivateHandler(event)
      expect(response.success).toBe(true)
      expect(authUtils.writeUsers).toHaveBeenCalled()
    })
  })

  describe('POST /api/cms/users/reject', () => {
    it('löscht Benutzer aus der Liste', async () => {
      const event = adminEvent()
      mockSuccessReadBody({ userId: '2' })
      authUtils.readUsers.mockResolvedValue([{ id: '1' }, { id: '2' }])
      authUtils.writeUsers.mockResolvedValue(true)

      const response = await usersRejectHandler(event)
      expect(response.success).toBe(true)
      expect(authUtils.writeUsers).toHaveBeenCalledWith([{ id: '1' }])
    })
  })

  describe('POST /api/cms/users/update-role', () => {
    it('validiert Rolle', async () => {
      const event = adminEvent()
      mockSuccessReadBody({ userId: '1', roles: ['invalid'] })

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

    it('aktualisiert Rolle', async () => {
      const event = adminEvent()
      mockSuccessReadBody({ userId: '1', roles: ['vorstand'] })
      authUtils.readUsers.mockResolvedValue([{ id: '1', roles: ['mitglied'] }])
      authUtils.writeUsers.mockResolvedValue(true)
      authUtils.migrateUserRoles.mockImplementation((user) => {
        if (!user) return user
        if (Array.isArray(user.roles)) return user
        if (user.role) {
          user.roles = [user.role]
          delete user.role
        } else {
          user.roles = ['mitglied']
        }
        return user
      })

      const response = await usersUpdateRoleHandler(event)
      expect(response.success).toBe(true)
      expect(authUtils.writeUsers).toHaveBeenCalled()
    })
  })
})
