import { Router, Response, NextFunction } from 'express'
import { v4 as uuidv4 } from 'uuid'
import { body, validationResult } from 'express-validator'
import bcrypt from 'bcryptjs'
import { db } from '../config/database'
import { authenticate, AuthRequest } from '../middleware/auth'
import { requirePermission, requireAdminPanel } from '../middleware/roleAuth'
import { User, UserRole } from '@skillmate/shared'

const router = Router()

// Get all users (admin only)
router.get('/', authenticate, requirePermission('users:read'), async (req: AuthRequest, res, next) => {
  try {
    const users = db.prepare(`
      SELECT id, username, email, role, employee_id, last_login, is_active, created_at, updated_at
      FROM users
      ORDER BY created_at DESC
    `).all()

    const formattedUsers: User[] = users.map((user: any) => ({
      id: user.id,
      username: user.username,
      email: user.email,
      role: user.role as UserRole,
      employeeId: user.employee_id || undefined,
      lastLogin: user.last_login ? new Date(user.last_login) : undefined,
      isActive: Boolean(user.is_active),
      createdAt: new Date(user.created_at),
      updatedAt: new Date(user.updated_at)
    }))

    res.json({
      success: true,
      data: formattedUsers
    })
  } catch (error) {
    next(error)
  }
})

// Get user by ID
router.get('/:id', authenticate, requirePermission('users:read'), async (req: AuthRequest, res, next) => {
  try {
    const { id } = req.params

    const user = db.prepare(`
      SELECT id, username, email, role, employee_id, last_login, is_active, created_at, updated_at
      FROM users 
      WHERE id = ?
    `).get(id)

    if (!user) {
      return res.status(404).json({ error: 'User not found' })
    }

    const userRecord = user as any
    const formattedUser: User = {
      id: userRecord.id,
      username: userRecord.username,
      email: userRecord.email,
      role: userRecord.role as UserRole,
      employeeId: userRecord.employee_id || undefined,
      lastLogin: userRecord.last_login ? new Date(userRecord.last_login) : undefined,
      isActive: Boolean(userRecord.is_active),
      createdAt: new Date(userRecord.created_at),
      updatedAt: new Date(userRecord.updated_at)
    }

    res.json({
      success: true,
      data: formattedUser
    })
  } catch (error) {
    next(error)
  }
})

// Create new user (admin only)
router.post('/',
  authenticate,
  requirePermission('users:create'),
  [
    body('username').notEmpty().trim().isLength({ min: 3 }),
    body('email').isEmail().normalizeEmail(),
    body('password').isLength({ min: 6 }),
    body('role').isIn(['admin', 'superuser', 'user']),
    body('employeeId').optional().isString()
  ],
  async (req: AuthRequest, res: Response, next: NextFunction) => {
    try {
      const errors = validationResult(req)
      if (!errors.isEmpty()) {
        return res.status(400).json({ 
          error: 'Validation failed',
          details: errors.array()
        })
      }

      const { username, email, password, role, employeeId } = req.body

      // Check if username already exists
      const existingUser = db.prepare('SELECT id FROM users WHERE username = ?').get(username)
      if (existingUser) {
        return res.status(409).json({ error: 'Username already exists' })
      }

      // Check if email already exists
      const existingEmail = db.prepare('SELECT id FROM users WHERE email = ?').get(email)
      if (existingEmail) {
        return res.status(409).json({ error: 'Email already exists' })
      }

      // Hash password
      const hashedPassword = bcrypt.hashSync(password, 10)
      const now = new Date().toISOString()
      const userId = uuidv4()

      // Enforce role policy: only admins can set role other than 'user'
      const assignedRole = (req.user?.role === 'admin') ? role : 'user'

      // Insert user
      db.prepare(`
        INSERT INTO users (id, username, email, password, role, employee_id, is_active, created_at, updated_at)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
      `).run(
        userId,
        username,
        email,
        hashedPassword,
        assignedRole,
        employeeId || null,
        1,
        now,
        now
      )

      const newUser: User = {
        id: userId,
        username,
        email,
        role: assignedRole as UserRole,
        employeeId: employeeId || undefined,
        isActive: true,
        createdAt: new Date(now),
        updatedAt: new Date(now)
      }

      res.status(201).json({
        success: true,
        data: newUser
      })
    } catch (error) {
      next(error)
    }
  }
)

// Update user (admin only)
router.put('/:id',
  authenticate,
  requirePermission('users:update'),
  [
    body('username').optional().trim().isLength({ min: 3 }),
    body('email').optional().isEmail().normalizeEmail(),
    body('password').optional().isLength({ min: 6 }),
    body('role').optional().isIn(['admin', 'superuser', 'user']),
    body('employeeId').optional().isString(),
    body('isActive').optional().isBoolean()
  ],
  async (req: AuthRequest, res: Response, next: NextFunction) => {
    try {
      const errors = validationResult(req)
      if (!errors.isEmpty()) {
        return res.status(400).json({ 
          error: 'Validation failed',
          details: errors.array()
        })
      }

      const { id } = req.params
      const { username, email, password, role, employeeId, isActive } = req.body

      // Check if user exists
      const existingUser = db.prepare('SELECT * FROM users WHERE id = ?').get(id)
      if (!existingUser) {
        return res.status(404).json({ error: 'User not found' })
      }

      // Prepare update fields
      const updates = []
      const values = []

      if (username) {
        // Check if new username is already taken (by another user)
        const usernameCheck = db.prepare('SELECT id FROM users WHERE username = ? AND id != ?').get(username, id)
        if (usernameCheck) {
          return res.status(409).json({ error: 'Username already exists' })
        }
        updates.push('username = ?')
        values.push(username)
      }

      if (email) {
        // Check if new email is already taken (by another user)
        const emailCheck = db.prepare('SELECT id FROM users WHERE email = ? AND id != ?').get(email, id)
        if (emailCheck) {
          return res.status(409).json({ error: 'Email already exists' })
        }
        updates.push('email = ?')
        values.push(email)
      }

      if (password) {
        const hashedPassword = bcrypt.hashSync(password, 10)
        updates.push('password = ?')
        values.push(hashedPassword)
      }

      if (role) {
        updates.push('role = ?')
        values.push(role)
      }

      if (employeeId !== undefined) {
        updates.push('employee_id = ?')
        values.push(employeeId || null)
      }

      if (isActive !== undefined) {
        updates.push('is_active = ?')
        values.push(isActive ? 1 : 0)
      }

      if (updates.length === 0) {
        return res.status(400).json({ error: 'No fields to update' })
      }

      updates.push('updated_at = ?')
      values.push(new Date().toISOString())
      values.push(id)

      db.prepare(`
        UPDATE users 
        SET ${updates.join(', ')}
        WHERE id = ?
      `).run(...values)

      // Return updated user
      const updatedUser = db.prepare(`
        SELECT id, username, email, role, employee_id, last_login, is_active, created_at, updated_at
        FROM users 
        WHERE id = ?
      `).get(id)

      const updatedRecord = updatedUser as any
      const formattedUser: User = {
        id: updatedRecord.id,
        username: updatedRecord.username,
        email: updatedRecord.email,
        role: updatedRecord.role as UserRole,
        employeeId: updatedRecord.employee_id || undefined,
        lastLogin: updatedRecord.last_login ? new Date(updatedRecord.last_login) : undefined,
        isActive: Boolean(updatedRecord.is_active),
        createdAt: new Date(updatedRecord.created_at),
        updatedAt: new Date(updatedRecord.updated_at)
      }

      res.json({
        success: true,
        data: formattedUser
      })
    } catch (error) {
      next(error)
    }
  }
)

// Delete user (admin only)
router.delete('/:id',
  authenticate,
  requirePermission('users:delete'),
  async (req: AuthRequest, res: Response, next: NextFunction) => {
    try {
      const { id } = req.params

      // Prevent deleting self
      if (req.user?.id === id) {
        return res.status(400).json({ error: 'Cannot delete your own account' })
      }

      // Check if user exists
      const existingUser = db.prepare('SELECT * FROM users WHERE id = ?').get(id)
      if (!existingUser) {
        return res.status(404).json({ error: 'User not found' })
      }

      // Delete user
      db.prepare('DELETE FROM users WHERE id = ?').run(id)

      res.json({
        success: true,
        message: 'User deleted successfully'
      })
    } catch (error) {
      next(error)
    }
  }
)

export default router
