import { Router, Response, NextFunction } from 'express'
import { body, validationResult } from 'express-validator'
import bcrypt from 'bcrypt'
import { v4 as uuidv4 } from 'uuid'
import { db, encryptedDb } from '../config/secureDatabase'
import { authenticate, authorize, AuthRequest } from '../middleware/auth'
import { User, UserRole } from '@skillmate/shared'
import { FieldEncryption } from '../services/encryption'
import { emailService } from '../services/emailService'
import { logger } from '../utils/logger'

const router = Router()

// Get all users (admin only)
router.get('/', authenticate, authorize('admin', 'superuser'), 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 username
    `).all() as any[]

    // Decrypt email addresses (handle decryption failures)
    const decryptedUsers = users.map(user => {
      let decryptedEmail = user.email
      
      // Check if email looks encrypted (encrypted strings are typically longer and contain special characters)
      if (user.email && user.email.includes('U2FsdGVkX1')) {
        try {
          decryptedEmail = FieldEncryption.decrypt(user.email) || user.email
        } catch (error) {
          logger.warn(`Failed to decrypt email for user ${user.username}, using raw value`)
          // For compatibility with old unencrypted data or different encryption keys
          decryptedEmail = user.email
        }
      }
      
      return {
        ...user,
        email: decryptedEmail,
        isActive: Boolean(user.is_active),
        lastLogin: user.last_login ? new Date(user.last_login) : null,
        createdAt: new Date(user.created_at),
        updatedAt: new Date(user.updated_at),
        employeeId: user.employee_id
      }
    })

    res.json({ success: true, data: decryptedUsers })
  } catch (error) {
    logger.error('Error fetching users:', error)
    next(error)
  }
})

// Update user role (admin only)
router.put('/:id/role', 
  authenticate, 
  authorize('admin'),
  [
    body('role').isIn(['admin', 'superuser', 'user'])
  ],
  async (req: AuthRequest, res: Response, next: NextFunction) => {
    try {
      const errors = validationResult(req)
      if (!errors.isEmpty()) {
        return res.status(400).json({ 
          success: false, 
          error: { message: 'Invalid input', details: errors.array() } 
        })
      }

      const { id } = req.params
      const { role } = req.body

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

      // Prevent changing admin user role
      if (existingUser.username === 'admin' && role !== 'admin') {
        return res.status(403).json({
          success: false,
          error: { message: 'Cannot change admin user role' }
        })
      }

      // Update role
      db.prepare(`
        UPDATE users SET role = ?, updated_at = ?
        WHERE id = ?
      `).run(role, new Date().toISOString(), id)

      logger.info(`User role updated: ${existingUser.username} -> ${role}`)
      res.json({ success: true, message: 'Role updated successfully' })
    } catch (error) {
      logger.error('Error updating user role:', error)
      next(error)
    }
  }
)

// Bulk create users from employees
router.post('/bulk-create-from-employees',
  authenticate,
  authorize('admin'),
  [
    body('employeeIds').isArray({ min: 1 }),
    body('role').isIn(['admin', 'superuser', 'user'])
  ],
  async (req: AuthRequest, res: Response, next: NextFunction) => {
    try {
      const errors = validationResult(req)
      if (!errors.isEmpty()) {
        return res.status(400).json({ 
          success: false, 
          error: { message: 'Invalid input', details: errors.array() } 
        })
      }

      const { employeeIds, role } = req.body as { employeeIds: string[]; role: UserRole }
      const results: any[] = []

      for (const employeeId of employeeIds) {
        try {
          const emp = encryptedDb.getEmployee(employeeId) as any
          if (!emp) {
            results.push({ employeeId, status: 'skipped', reason: 'employee_not_found' })
            continue
          }

          const existsByEmployee = db.prepare('SELECT id FROM users WHERE employee_id = ?').get(employeeId)
          if (existsByEmployee) {
            results.push({ employeeId, status: 'skipped', reason: 'user_exists' })
            continue
          }

          const baseUsername = (emp.email ? String(emp.email).split('@')[0] : `${emp.first_name}.${emp.last_name}`)
            .toLowerCase().replace(/\s+/g, '')
          let finalUsername = baseUsername
          let i = 1
          while (db.prepare('SELECT id FROM users WHERE username = ?').get(finalUsername)) {
            finalUsername = `${baseUsername}${i++}`
          }

          const email: string | null = emp.email || null
          const tempPassword = `Temp${Math.random().toString(36).slice(-8)}!@#`
          const hashedPassword = await bcrypt.hash(tempPassword, 12)
          const now = new Date().toISOString()
          const userId = uuidv4()

          db.prepare(`
            INSERT INTO users (id, username, email, email_hash, password, role, employee_id, is_active, created_at, updated_at)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
          `).run(
            userId,
            finalUsername,
            email ? FieldEncryption.encrypt(email) : null,
            email ? FieldEncryption.hash(email) : null,
            hashedPassword,
            role,
            employeeId,
            1,
            now,
            now
          )

          results.push({ employeeId, status: 'created', username: finalUsername, temporaryPassword: tempPassword })
        } catch (err: any) {
          logger.error('Bulk create error for employee ' + employeeId, err)
          results.push({ employeeId, status: 'error', reason: err?.message || 'unknown_error' })
        }
      }

      return res.status(201).json({ success: true, data: { results } })
    } catch (error) {
      logger.error('Error in bulk create from employees:', error)
      next(error)
    }
  }
)

// Update user status (admin only)
router.put('/:id/status', 
  authenticate, 
  authorize('admin'),
  [
    body('isActive').isBoolean()
  ],
  async (req: AuthRequest, res: Response, next: NextFunction) => {
    try {
      const errors = validationResult(req)
      if (!errors.isEmpty()) {
        return res.status(400).json({ 
          success: false, 
          error: { message: 'Invalid input', details: errors.array() } 
        })
      }

      const { id } = req.params
      const { isActive } = req.body

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

      // Prevent deactivating admin user
      if (existingUser.username === 'admin' && !isActive) {
        return res.status(403).json({
          success: false,
          error: { message: 'Cannot deactivate admin user' }
        })
      }

      // Update status
      db.prepare(`
        UPDATE users SET is_active = ?, updated_at = ?
        WHERE id = ?
      `).run(isActive ? 1 : 0, new Date().toISOString(), id)

      logger.info(`User status updated: ${existingUser.username} -> ${isActive ? 'active' : 'inactive'}`)
      res.json({ success: true, message: 'Status updated successfully' })
    } catch (error) {
      logger.error('Error updating user status:', error)
      next(error)
    }
  }
)

// Reset user password (admin only)
router.post('/:id/reset-password', 
  authenticate, 
  authorize('admin'),
  [
    body('newPassword').optional().isLength({ min: 8 })
  ],
  async (req: AuthRequest, res: Response, next: NextFunction) => {
    try {
      const errors = validationResult(req)
      if (!errors.isEmpty()) {
        return res.status(400).json({ 
          success: false, 
          error: { message: 'Invalid input', details: errors.array() } 
        })
      }

      const { id } = req.params
      const { newPassword } = req.body

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

      // Generate password
      const password = newPassword || `Temp${Math.random().toString(36).slice(-8)}!@#`
      const hashedPassword = await bcrypt.hash(password, 12)

      // Update password
      db.prepare(`
        UPDATE users SET password = ?, updated_at = ?
        WHERE id = ?
      `).run(hashedPassword, new Date().toISOString(), id)

      logger.info(`Password reset for user: ${existingUser.username}`)
      
      res.json({ 
        success: true, 
        message: 'Password reset successfully',
        data: { temporaryPassword: newPassword ? undefined : password }
      })
    } catch (error) {
      logger.error('Error resetting password:', error)
      next(error)
    }
  }
)

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

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

      // Prevent deleting admin user
      if (existingUser.username === 'admin') {
        return res.status(403).json({
          success: false,
          error: { message: 'Cannot delete admin user' }
        })
      }

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

      logger.info(`User deleted: ${existingUser.username}`)
      res.json({ success: true, message: 'User deleted successfully' })
    } catch (error) {
      logger.error('Error deleting user:', error)
      next(error)
    }
  }
)

export default router

// Create user account from existing employee (admin only)
router.post('/create-from-employee',
  authenticate,
  authorize('admin'),
  [
    body('employeeId').notEmpty().isString(),
    body('username').optional().isString().isLength({ min: 3 }),
    body('role').isIn(['admin', 'superuser', 'user'])
  ],
  async (req: AuthRequest, res: Response, next: NextFunction) => {
    try {
      const errors = validationResult(req)
      if (!errors.isEmpty()) {
        return res.status(400).json({
          success: false,
          error: { message: 'Invalid input', details: errors.array() }
        })
      }

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

      // Check employee exists
      const employee = encryptedDb.getEmployee(employeeId) as any
      if (!employee) {
        return res.status(404).json({ success: false, error: { message: 'Employee not found' } })
      }

      // Check if a user is already linked to this employee
      const existingByEmployee = db.prepare('SELECT id FROM users WHERE employee_id = ?').get(employeeId)
      if (existingByEmployee) {
        return res.status(409).json({ success: false, error: { message: 'User already exists for this employee' } })
      }

      // Determine email and username
      const email: string | null = employee.email || null
      const finalUsername = username || (email ? String(email).split('@')[0] : `${employee.first_name}.${employee.last_name}`)

      // Check username uniqueness
      const usernameExists = db.prepare('SELECT id FROM users WHERE username = ?').get(finalUsername)
      if (usernameExists) {
        return res.status(409).json({ success: false, error: { message: 'Username already exists' } })
      }

      // Check email uniqueness if available
      if (email) {
        const emailHash = FieldEncryption.hash(email)
        const emailExists = db.prepare('SELECT id FROM users WHERE email_hash = ?').get(emailHash)
        if (emailExists) {
          return res.status(409).json({ success: false, error: { message: 'Email already used by another account' } })
        }
      }

      // Generate temp password
      const tempPassword = `Temp${Math.random().toString(36).slice(-8)}!@#`
      const hashedPassword = await bcrypt.hash(tempPassword, 12)
      const now = new Date().toISOString()
      const userId = uuidv4()

      // Insert user with encrypted email
      db.prepare(`
        INSERT INTO users (id, username, email, email_hash, password, role, employee_id, is_active, created_at, updated_at)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
      `).run(
        userId,
        finalUsername,
        email ? FieldEncryption.encrypt(email) : null,
        email ? FieldEncryption.hash(email) : null,
        hashedPassword,
        role,
        employeeId,
        1,
        now,
        now
      )

      logger.info(`User created from employee ${employeeId}: ${finalUsername} (${role})`)
      return res.status(201).json({ success: true, data: { id: userId, username: finalUsername, temporaryPassword: tempPassword } })
    } catch (error) {
      logger.error('Error creating user from employee:', error)
      next(error)
    }
  }
)

// Purge users: keep only admin and one specified email (admin only)
router.post('/purge',
  authenticate,
  authorize('admin'),
  [
    body('email').isEmail()
  ],
  async (req: AuthRequest, res: Response, next: NextFunction) => {
    try {
      const errors = validationResult(req)
      if (!errors.isEmpty()) {
        return res.status(400).json({
          success: false,
          error: { message: 'Invalid input', details: errors.array() }
        })
      }

      const { email } = req.body as { email: string }
      const emailHash = FieldEncryption.hash(email)

      const total = (db.prepare('SELECT COUNT(*) as c FROM users').get() as any).c || 0
      const keep = db.prepare('SELECT id, username FROM users WHERE username = ? OR email_hash = ?').all('admin', emailHash) as any[]

      const delStmt = db.prepare('DELETE FROM users WHERE username <> ? AND (email_hash IS NULL OR email_hash <> ?)')
      const info = delStmt.run('admin', emailHash)

      logger.warn(`User purge executed by ${req.user?.username}. Kept ${keep.length}, deleted ${info.changes}.`)
      return res.json({ success: true, data: { total, kept: keep.length, deleted: info.changes } })
    } catch (error) {
      logger.error('Error purging users:', error)
      next(error)
    }
  }
)

// Send temporary password via email to user's email
router.post('/:id/send-temp-password',
  authenticate,
  authorize('admin'),
  [
    body('password').notEmpty().isString().isLength({ min: 6 })
  ],
  async (req: AuthRequest, res: Response, next: NextFunction) => {
    try {
      const errors = validationResult(req)
      if (!errors.isEmpty()) {
        return res.status(400).json({
          success: false,
          error: { message: 'Invalid input', details: errors.array() }
        })
      }

      const { id } = req.params
      const { password } = req.body as { password: string }

      // Load user
      const user = db.prepare('SELECT id, username, email, employee_id FROM users WHERE id = ?').get(id) as any
      if (!user) {
        return res.status(404).json({ success: false, error: { message: 'User not found' } })
      }

      // Decrypt email
      const email = user.email ? FieldEncryption.decrypt(user.email) : null
      if (!email) {
        return res.status(400).json({ success: false, error: { message: 'User has no email address' } })
      }

      // Optional: get first name for nicer email copy
      let firstName: string | undefined = undefined
      if (user.employee_id) {
        const emp = encryptedDb.getEmployee(user.employee_id)
        if (emp && emp.first_name) firstName = emp.first_name
      }

      const emailNotificationsSetting = db.prepare('SELECT value FROM system_settings WHERE key = ?').get('email_notifications_enabled') as any
      const emailNotificationsEnabled = emailNotificationsSetting?.value === 'true'

      if (!emailNotificationsEnabled || !emailService.isServiceEnabled()) {
        return res.status(503).json({ success: false, error: { message: 'Email service not enabled' } })
      }

      const sent = await emailService.sendInitialPassword(email, password, firstName)
      if (!sent) {
        return res.status(500).json({ success: false, error: { message: 'Failed to send email' } })
      }

      logger.info(`Temporary password email sent to ${email} for user ${user.username}`)
      return res.json({ success: true, message: 'Temporary password email sent' })
    } catch (error) {
      logger.error('Error sending temporary password email:', error)
      next(error)
    }
  }
)
