const { validationResult } = require('express-validator')
const bcrypt = require('bcryptjs')
const User = require('../models/User')
const Unit = require('../models/Unit')
const Department = require('../models/Department')
const { ensureAbsoluteUrl, ensureImagesRelativePath } = require('../middleware/fileUpload')

class UserController {
  // Create new user
  static async createUser (req, res, next) {
    try {
      const errors = validationResult(req)
      if (!errors.isEmpty()) {
        return res.status(400).json({ status: 'error', message: 'Validation failed', errors: errors.array() })
      }

      const { name, phone, email, role_id, organization_id, login_id, password, avatar, logo, status, is_active, is_login, is_password_changed } = req.body

      const isSuperAdmin = (req.user?.role_id === 1) || String(req.user?.role || '').toLowerCase() === 'super_admin'
      let orgId = req.user?.organization_id || null
      if (isSuperAdmin && organization_id) {
        orgId = parseInt(organization_id)
      }
      if (!orgId) {
        orgId = organization_id ? parseInt(organization_id) : 1
      }

      if (!role_id || !orgId) {
        return res.status(400).json({ status: 'error', message: 'Role and Organization are mandatory' })
      }

      // If login access is requested, require both login_id and password
      const wantsLoginAccess = !!login_id || !!password || (!!is_login && String(is_login) !== 'false')
      if (wantsLoginAccess) {
        if (!login_id) {
          return res.status(400).json({ status: 'error', message: 'Login ID is required when login access is enabled' })
        }
        if (!password || String(password).trim().length < 6) {
          return res.status(400).json({ status: 'error', message: 'Password (min 6 chars) is required when login access is enabled' })
        }
      }

      if (login_id) {
        const existingLogin = await User.findByLoginId(String(login_id).trim())
        if (existingLogin && existingLogin.is_active) {
          return res.status(400).json({ status: 'error', message: 'Login ID already exists' })
        }
      }

      const password_hash = login_id ? await bcrypt.hash(String(password).trim(), 12) : null

      let logoPath = null
      if (req.file) {
        const { buildPublicUploadPath } = require('../middleware/fileUpload')
        logoPath = buildPublicUploadPath('user', req.file.filename)
      } else if (req.body.logo) {
        logoPath = req.body.logo
      }

      const userId = await User.create({
        name: name || null,
        organization_id: orgId,
        role_id: parseInt(role_id),
        phone: phone || null,
        email: email || null,
        login_id: login_id ? String(login_id).trim() : null,
        password_hash,
        status: status || 'offline',
        is_active: (is_active === undefined || is_active === null) ? true : !!is_active,
        is_login: (is_login === undefined || is_login === null) ? !!login_id : !!is_login,
        is_password_changed: (is_password_changed === undefined || is_password_changed === null) ? false : !!is_password_changed,
        avatar: avatar || null,
        logo: logoPath || null
      })

      const newUser = await User.findById(userId)
      const ju = newUser.toJSON()
      try {
        if (ju.logo) {
          const rel = ensureImagesRelativePath('contacts', ju.logo)
          const abs = rel ? ensureAbsoluteUrl(req, rel) : null
          ju.logo = abs
          ju.logo_url = abs
        }
        if (ju.avatar) {
          const relA = ensureImagesRelativePath('contacts', ju.avatar)
          const absA = relA ? ensureAbsoluteUrl(req, relA) : null
          ju.avatar = absA
          ju.avatar_url = absA
        }
      } catch {}
      res.status(201).json({ status: 'success', message: 'User created successfully', data: { user: ju } })
    } catch (error) {
      next(error)
    }
  }

  // Get all users with filtering
  static async getAllUsers (req, res, _next) {
    try {
      const {
        page = 1,
        limit = 50,
        search = '',
        unit_id = '',
        department_id = '',
        role_id = '',
        parent_id = null,
        include_inactive = 'false'
      } = req.query

      const organization_id = req.user?.organization_id

      const options = {
        page: parseInt(page),
        limit: parseInt(limit),
        search,
        unit_id,
        department_id,
        role_id,
        parent_id,
        organization_id,
        include_inactive: include_inactive === 'true'
      }

      const users = await User.findAll(options)
      const statistics = await User.getStatistics()

      res.status(200).json({
        status: 'success',
        message: 'Users retrieved successfully',
        data: {
          users: users.map(user => ({
            id: user.id,
            name: user.name,
            organization_id: user.organization_id,
            service_no: user.service_no,
            email: user.email,
            unit_name: user.unit_name,
            department_name: user.department_name,
            designation_name: user.designation_name,
            role_name: user.role_name,
            parent_name: user.parent_name,
            is_active: user.is_active,
            status: user.status,
            created_at: user.created_at
          })),
          statistics,
          pagination: {
            page: parseInt(page),
            limit: parseInt(limit),
            total: users.length
          },
          filters: {
            search,
            unit_id,
            department_id,
            role_id,
            include_inactive: include_inactive === 'true'
          }
        }
      })
    } catch (error) {
      console.error('Error in getAllUsers:', error)
      return res.status(500).json({
        status: 'error',
        message: 'Error retrieving users',
        error: error.message
      })
    }
  }

  // Get user by ID
  static async getUserById (req, res, next) {
    try {
      const { id } = req.params
      const user = await User.findById(id)

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

      const u = user.toJSON()
      try {
        if (u.logo) {
          const rel = ensureImagesRelativePath('user', u.logo)
          const abs = rel ? ensureAbsoluteUrl(req, rel) : null
          u.logo = abs
          u.logo_url = abs
        }
        if (u.avatar) {
          const relA = ensureImagesRelativePath('user', u.avatar)
          const absA = relA ? ensureAbsoluteUrl(req, relA) : null
          u.avatar = absA
          u.avatar_url = absA
        }
      } catch {}
      res.status(200).json({
        status: 'success',
        message: 'User retrieved successfully',
        data: {
          user: u
        }
      })
    } catch (error) {
      next(error)
    }
  }

  // Update user
  static async updateUser (req, res, next) {
    try {
      const errors = validationResult(req)
      if (!errors.isEmpty()) {
        return res.status(400).json({ status: 'error', message: 'Validation failed', errors: errors.array() })
      }

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

      const user = await User.findById(id)
      if (!user) {
        return res.status(404).json({ status: 'error', message: 'User not found' })
      }

      if (Object.prototype.hasOwnProperty.call(updateData, 'login_id')) {
        const desired = String(updateData.login_id || '').trim()
        if (desired) {
          const existing = await User.findByLoginId(desired)
          if (existing && existing.id !== user.id) {
            return res.status(400).json({ status: 'error', message: 'Login ID already exists' })
          }
        }
      }

      if (updateData.password) {
        updateData.password_hash = await bcrypt.hash(String(updateData.password).trim(), 12)
        delete updateData.password
      }

      if (req.file) {
        const { buildPublicUploadPath } = require('../middleware/fileUpload')
        updateData.logo = buildPublicUploadPath('user', req.file.filename)
      } else if (req.body.remove_logo === 'true' || req.body.remove_logo === true) {
        updateData.logo = null
      }

      const updated = await User.update(id, updateData)

      if (!updated) {
        return res.status(400).json({ status: 'error', message: 'User not found or no changes made' })
      }

      const updatedUser = await User.findById(id)
      const ju = updatedUser.toJSON()
      try {
        if (ju.logo) {
          const rel = ensureImagesRelativePath('user', ju.logo)
          const abs = rel ? ensureAbsoluteUrl(req, rel) : null
          ju.logo = abs
          ju.logo_url = abs
        }
        if (ju.avatar) {
          const relA = ensureImagesRelativePath('user', ju.avatar)
          const absA = relA ? ensureAbsoluteUrl(req, relA) : null
          ju.avatar = absA
          ju.avatar_url = absA
        }
      } catch {}
      res.status(200).json({ status: 'success', message: 'User updated successfully', data: { user: ju } })
    } catch (error) {
      next(error)
    }
  }

  // Delete user (soft delete)
  static async deleteUser (req, res, next) {
    try {
      const { id } = req.params

      // Check if user has children
      const children = await User.findByParentId(id)
      if (children.length > 0) {
        return res.status(400).json({
          status: 'error',
          message: 'Cannot delete user with subordinates. Please reassign or delete subordinates first.'
        })
      }

      const deleted = await User.delete(id)

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

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

  // Get user statistics
  static async getUserStatistics (req, res, next) {
    try {
      const statistics = await User.getStatistics()

      res.status(200).json({
        status: 'success',
        message: 'User statistics retrieved successfully',
        data: {
          statistics
        }
      })
    } catch (error) {
      next(error)
    }
  }
}

module.exports = UserController
