const { validationResult } = require('express-validator')
const Department = require('../models/Department')
const Unit = require('../models/Unit')
const { ensureAbsoluteUrl } = require('../middleware/fileUpload')
const { buildPublicUploadPath } = require('../middleware/fileUpload')

const parseNullableInt = (value) => {
  if (value === null || value === undefined || value === '') {
    return null
  }
  const parsed = parseInt(value, 10)
  return Number.isNaN(parsed) ? null : parsed
}

class DepartmentController {
  static addLogoUrl (req, department) {
    if (!department) return null
    const dep = typeof department.toJSON === 'function' ? department.toJSON() : department
    if (dep && dep.logo) {
      try {
        dep.logo = ensureAbsoluteUrl(req, dep.logo)
      } catch {}
    }
    return dep
  }
  // Get all departments
  static async getAllDepartments (req, res, next) {
    try {
      console.log('Departments:getAllDepartments request', {
        query: req.query,
        user: req.user ? { id: req.user.id, role_id: req.user.role_id, role: req.user.role, organization_id: req.user.organization_id } : null
      })
      const {
        page = 1,
        limit = 1000, // Increased default limit to get all departments
        search = '',
        include_inactive = 'false',
        organization_id: requested_org_id = ''
      } = req.query

      let organization_id = req.user?.organization_id
      const reqOrgParsed = requested_org_id ? parseInt(requested_org_id, 10) : null
      const isSuperAdmin = (user) => {
        if (!user) return false
        const roleName = (user.role || '').toLowerCase()
        return user.role_id === 1 || roleName === 'super admin' || roleName === 'super_admin'
      }
      if (isSuperAdmin(req.user)) {
        organization_id = reqOrgParsed || null
      }

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

      console.log('Departments:getAllDepartments options', options)
      const departments = await Department.findAll(options)
      const totalItems = await Department.countAll(options)
      const statistics = await Department.getStatistics()

      // Set cache-control headers to prevent browser caching
      res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
      res.setHeader('Pragma', 'no-cache')
      res.setHeader('Expires', '0')

      res.status(200).json({
        status: 'success',
        message: 'Departments retrieved successfully',
        data: {
          departments: departments.map(dept => DepartmentController.addLogoUrl(req, dept)),
          statistics,
          pagination: {
            current_page: options.page,
            total_pages: Math.max(1, Math.ceil(totalItems / options.limit)),
            total_items: totalItems
          },
          filters: {
            search,
            include_inactive: include_inactive === 'true'
          }
        }
      })
    } catch (error) {
      console.error('Departments:getAllDepartments error', {
        message: error.message,
        stack: error.stack
      })
      next(error)
    }
  }

  // Get department by ID
  static async getDepartmentById (req, res, next) {
    try {
      const { id } = req.params
      const isSuperAdmin = (user) => {
        if (!user) return false
        const roleName = (user.role || '').toLowerCase()
        return user.role_id === 1 || roleName === 'super admin' || roleName === 'super_admin'
      }
      const organization_id = isSuperAdmin(req.user) ? null : req.user?.organization_id
      const department = await Department.findById(id, organization_id)

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

      res.status(200).json({
        status: 'success',
        message: 'Department retrieved successfully',
        data: {
          department: DepartmentController.addLogoUrl(req, department)
        }
      })
    } catch (error) {
      next(error)
    }
  }

  // Get departments by unit - no longer supported

  // Create new department
  static async createDepartment (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,
        order_id,
        parent_id,
        description,
        organization_id: bodyOrganizationId
      } = req.body
      const isSuperAdmin = (user) => {
        if (!user) return false
        const roleName = (user.role || '').toLowerCase()
        return user.role_id === 1 || roleName === 'super admin' || roleName === 'super_admin'
      }
      const parsedBodyOrgId = bodyOrganizationId ? parseInt(bodyOrganizationId, 10) : null
      const organization_id = isSuperAdmin(req.user) ? (parsedBodyOrgId || req.user?.organization_id || 1) : (req.user?.organization_id || 1)
      let normalizedParentId = parseNullableInt(parent_id)
      let parentDepartment = null
      if (normalizedParentId) {
        parentDepartment = await Department.findById(normalizedParentId, organization_id)
        if (!parentDepartment) {
          normalizedParentId = null
        }
      }

      let logoPath = null
      if (req.file) {
        logoPath = buildPublicUploadPath('department', req.file.filename)
      } else if (req.body.logo) {
        logoPath = req.body.logo
      }

      const departmentId = await Department.create({
        name,
        organization_id,
        order_id,
        parent_id: normalizedParentId,
        description,
        logo: logoPath
      })

      const newDepartment = await Department.findById(departmentId, organization_id)

      res.status(201).json({
        status: 'success',
        message: 'Department created successfully',
        data: {
          department: DepartmentController.addLogoUrl(req, newDepartment)
        }
      })
    } catch (error) {
      next(error)
    }
  }

  // Update department
  static async updateDepartment (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 isSuperAdmin = (user) => {
        if (!user) return false
        const roleName = (user.role || '').toLowerCase()
        return user.role_id === 1 || roleName === 'super admin' || roleName === 'super_admin'
      }

      const bodyOrgIdRaw = updateData.organization_id
      const bodyOrgIdParsed = bodyOrgIdRaw ? parseInt(bodyOrgIdRaw, 10) : null
      const organization_id = isSuperAdmin(req.user) ? null : req.user?.organization_id

      // Normalize parent_id to integer/null
      if (Object.prototype.hasOwnProperty.call(updateData, 'parent_id')) {
        const parsedParentId = parseNullableInt(updateData.parent_id)
        updateData.parent_id = parsedParentId
      }

      // Handle logo removal flag
      const removeLogoRequested = updateData.remove_logo === 'true' || updateData.remove_logo === true || updateData.remove_logo === '1'
      if (removeLogoRequested) {
        updateData.logo = null
      }
      delete updateData.remove_logo

      // Handle uploaded logo file
      if (req.file) {
        updateData.logo = buildPublicUploadPath('department', req.file.filename)
      }

      // Check if department exists (include inactive to allow re-activation or metadata edits)
      const department = await Department.findById(id, organization_id, true)
      if (!department) {
        return res.status(404).json({
          status: 'error',
          message: 'Department not found'
        })
      }

      // Remove unit_id handling

      // If parent_id is being updated, verify it exists and is valid
      if (updateData.parent_id !== undefined) {
        if (updateData.parent_id) {
          const parentDepartment = await Department.findById(updateData.parent_id, organization_id, true)
          if (!parentDepartment) {
            // Parent no longer exists – clear parent instead of blocking update
            updateData.parent_id = null
          } else {
            // No unit alignment needed

            // Check for circular references
            const canBeParent = await Department.canBeParent(id, updateData.parent_id)
            if (!canBeParent) {
              return res.status(400).json({
                status: 'error',
                message: 'Cannot set parent: would create circular reference'
              })
            }
          }
        }
      }

      const updated = await Department.update(id, updateData, organization_id, true)

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

      const updatedDepartment = await Department.findById(id, organization_id, true)

      res.status(200).json({
        status: 'success',
        message: 'Department updated successfully',
        data: {
          department: DepartmentController.addLogoUrl(req, updatedDepartment) || { id: parseInt(id, 10) }
        }
      })
    } catch (error) {
      next(error)
    }
  }

  // Delete department
  static async deleteDepartment (req, res, next) {
    try {
      const { id } = req.params

      const deleted = await Department.delete(id)

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

      res.status(200).json({
        status: 'success',
        message: 'Department deleted successfully'
      })
    } catch (error) {
      if (error.message.includes('Cannot delete')) {
        return res.status(400).json({
          status: 'error',
          message: error.message
        })
      }
      next(error)
    }
  }

  // Get department statistics
  static async getDepartmentStatistics (req, res, next) {
    try {
      const statistics = await Department.getStatistics()

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

  // Get department hierarchy
  static async getDepartmentHierarchy (req, res, next) {
    try {
      const hierarchy = await Department.getHierarchy()

      res.status(200).json({
        status: 'success',
        message: 'Department hierarchy retrieved successfully',
        data: {
          hierarchy,
          total_departments: hierarchy.length
        }
      })
    } catch (error) {
      next(error)
    }
  }

  // Get child departments
  static async getChildDepartments (req, res, next) {
    try {
      const { id } = req.params

      // Verify parent department exists
      const parentDepartment = await Department.findById(id)
      if (!parentDepartment) {
        return res.status(404).json({
          status: 'error',
          message: 'Department not found'
        })
      }

      const children = await Department.getChildren(id)

      res.status(200).json({
        status: 'success',
        message: 'Child departments retrieved successfully',
        data: {
          parent: parentDepartment.toJSON(),
          children: children.map(child => child.toJSON()),
          total_children: children.length
        }
      })
    } catch (error) {
      next(error)
    }
  }
}

module.exports = DepartmentController
