import prisma from './prisma';

/**
 * Collection of utility functions for working with departments
 */
export const DepartmentUtils = {
  /**
   * Create a new department
   * 
   * @param {Object} data Department data
   * @param {string} data.dp_name Department name
   * @param {number} data.org_id Organization ID
   * @returns {Promise<Object>} Created department
   */
  async create(data) {
    if (!data.dp_name) {
      throw new Error('Department name is required');
    }
    
    if (!data.org_id) {
      throw new Error('Organization ID is required');
    }
    
    // Check if organization exists
    const organization = await prisma.organization.findUnique({
      where: {
        org_id: parseInt(data.org_id)
      }
    });
    
    if (!organization) {
      throw new Error(`Organization with ID ${data.org_id} not found`);
    }
    
    return prisma.department.create({
      data: {
        dp_name: data.dp_name,
        org_id: parseInt(data.org_id)
      }
    });
  },
  
  /**
   * Get all departments with pagination and filtering
   * 
   * @param {Object} options Query options
   * @param {number} options.page Page number
   * @param {number} options.limit Items per page
   * @param {string} options.search Search term
   * @param {number} options.orgId Filter by organization ID
   * @returns {Promise<Object>} Departments and pagination metadata
   */
  async getAll({ page = 1, limit = 10, search = '', orgId = null }) {
    const skip = (page - 1) * limit;
    
    // Define filters
    const filters = {
      where: {}
    };
    
    // Filter by organization if provided
    if (orgId) {
      filters.where.org_id = parseInt(orgId);
    }
    
    // Add search filter if provided
    if (search) {
      filters.where = {
        ...filters.where,
        dp_name: {
          contains: search
        }
      };
    }
    
    // Get departments with pagination
    const [departments, total] = await Promise.all([
      prisma.department.findMany({
        ...filters,
        skip,
        take: limit,
        orderBy: {
          dp_name: 'asc'
        },
        include: {
          organization: {
            select: {
              org_id: true,
              org_name: true
            }
          },
          _count: {
            select: {
              cabinets: true,
              user: true
            }
          }
        }
      }),
      prisma.department.count(filters)
    ]);
    
    // Calculate pagination metadata
    const totalPages = Math.ceil(total / limit);
    
    return {
      departments,
      pagination: {
        page,
        limit,
        total,
        totalPages,
        hasNextPage: page < totalPages,
        hasPrevPage: page > 1
      }
    };
  },
  
  /**
   * Get department by ID
   * 
   * @param {number} id Department ID
   * @returns {Promise<Object|null>} Department or null if not found
   */
  async getById(id) {
    if (isNaN(parseInt(id))) {
      throw new Error('Invalid department ID');
    }
    
    return prisma.department.findUnique({
      where: {
        dp_id: parseInt(id)
      },
      include: {
        organization: {
          select: {
            org_id: true,
            org_name: true,
            org_country: true,
            org_state: true,
            org_active: true
          }
        },
        cabinets: {
          select: {
            cb_id: true
          }
        },
        user: {
          select: {
            userID: true,
            userUsername: true,
            userFullName: true,
            userEmail: true,
            userStatus: true
          }
        }
      }
    });
  },
  
  /**
   * Update a department
   * 
   * @param {number} id Department ID
   * @param {Object} data Department data
   * @returns {Promise<Object>} Updated department
   */
  async update(id, data) {
    if (isNaN(parseInt(id))) {
      throw new Error('Invalid department ID');
    }
    
    // Check if department exists
    const existingDept = await prisma.department.findUnique({
      where: {
        dp_id: parseInt(id)
      }
    });
    
    if (!existingDept) {
      throw new Error('Department not found');
    }
    
    // Validate required fields
    if (!data.dp_name) {
      throw new Error('Department name is required');
    }
    
    // If org_id is provided, check if organization exists
    if (data.org_id !== undefined) {
      const orgId = parseInt(data.org_id);
      
      if (isNaN(orgId)) {
        throw new Error('Invalid organization ID format');
      }
      
      const organization = await prisma.organization.findUnique({
        where: {
          org_id: orgId
        }
      });
      
      if (!organization) {
        throw new Error(`Organization with ID ${data.org_id} not found`);
      }
    }
    
    return prisma.department.update({
      where: {
        dp_id: parseInt(id)
      },
      data: {
        dp_name: data.dp_name,
        org_id: data.org_id !== undefined ? parseInt(data.org_id) : existingDept.org_id
      }
    });
  },
  
  /**
   * Delete a department
   * 
   * @param {number} id Department ID
   * @returns {Promise<Object>} Deleted department
   */
  async delete(id) {
    if (isNaN(parseInt(id))) {
      throw new Error('Invalid department ID');
    }
    
    // Check if department exists and get related entities
    const existingDept = await prisma.department.findUnique({
      where: {
        dp_id: parseInt(id)
      },
      include: {
        cabinets: {
          select: {
            cb_id: true
          }
        },
        user: {
          select: {
            userID: true
          }
        }
      }
    });
    
    if (!existingDept) {
      throw new Error('Department not found');
    }
    
    // Check if department has related cabinets
    if (existingDept.cabinets.length > 0) {
      throw new Error(`Cannot delete department with existing cabinets. Remove all cabinets first (${existingDept.cabinets.length} found).`);
    }
    
    // Check if department has related users
    if (existingDept.user.length > 0) {
      throw new Error(`Cannot delete department with existing users. Reassign or remove all users first (${existingDept.user.length} found).`);
    }
    
    return prisma.department.delete({
      where: {
        dp_id: parseInt(id)
      }
    });
  },
  
  /**
   * Get departments by organization ID
   * 
   * @param {number} orgId Organization ID
   * @returns {Promise<Array>} List of departments
   */
  async getByOrganization(orgId) {
    if (isNaN(parseInt(orgId))) {
      throw new Error('Invalid organization ID');
    }
    
    return prisma.department.findMany({
      where: {
        org_id: parseInt(orgId)
      },
      orderBy: {
        dp_name: 'asc'
      },
      include: {
        _count: {
          select: {
            cabinets: true,
            user: true
          }
        }
      }
    });
  }
};

export default DepartmentUtils; 