import { Injectable } from "@nestjs/common"
import { Department } from "../entities/department.entity"
import { CreateDepartmentDto } from "../dto/create-department.dto"
import { FindAllDepartmentDto } from "../dto/find-all-department.dto"
import { UpdateDepartmentDto } from "../dto/update-department.dto"
import { DepartmentRepository } from "../repositories/department.repository"
import { failureResponse } from "src/common/response/response"
import { isEmpty, successMessage } from "src/utils/helpers"
import { messageKey } from "src/constants/message-keys"
import { code } from "src/common/response/response.code"

@Injectable()
export class DepartmentService {
  constructor(private readonly departmentRepository: DepartmentRepository) {}

  async checkDepartmentExist(
    name: string,
    excludeId?: number,
  ): Promise<boolean> {
    const whereCondition: any = {}
    const wherelowerCondition: any = {
      name,
    }

    if (excludeId) {
      whereCondition["id"] = {
        not: excludeId,
      }
    }

    const currency = await this.departmentRepository.getByParams({
      where: whereCondition,
      whereLower: wherelowerCondition,
      findOne: true,
    })

    return !isEmpty(currency)
  }

  async createDepartment(createDepartmentDto: CreateDepartmentDto) {
    const isDepartmentExist = await this.checkDepartmentExist(
      createDepartmentDto.name,
    )

    if (isDepartmentExist) {
      return failureResponse(400, messageKey.already_exist)
    }

    try {
      const result = await this.departmentRepository.save({
        name: createDepartmentDto.name,
        description: createDepartmentDto.description,
      })

      return result
    } catch (error) {
      return failureResponse(500, messageKey.something_went_wrong)
    }
  }

  async findAllDepartments(params: FindAllDepartmentDto) {
    try {
      const validSortColumns = ["id", "name", "created_at", "updated_at"]

      let sortColumn: string
      let sortOrder: "ASC" | "DESC"

      // Validate sortBy and sortOrder
      if (params.sortBy && validSortColumns.includes(params.sortBy)) {
        sortColumn = params.sortBy
        sortOrder = params.sortOrder || "ASC"
      } else {
        sortColumn = "created_at"
        sortOrder = "DESC"
      }

      // Fetch departments
      const departments = (await this.departmentRepository.getByParams({
        search: {
          name: params.search,
          description: params.search,
        },
        take: Number(params.limit),
        skip: Number(params.skip),
        orderBy: {
          [sortColumn]: sortOrder,
        },
        relations: ["team_members"],
      })) as any

      // Add member count to departments
      const departmentsWithMemberCount = departments.data.map((department) => ({
        ...department,
        member_count: department.team_members
          ? department.team_members.length
          : 0,
      }))

      return {
        count: departments.count,
        data: departmentsWithMemberCount,
      }
    } catch (error) {
      return failureResponse(500, messageKey.something_went_wrong)
    }
  }

  async findOneDepartment(id: number): Promise<Department> {
    const department = (await this.departmentRepository.getByParams({
      where: { id },
      findOne: true,
    })) as Department

    if (!department) {
      throw new Error(messageKey.data_not_found)
    }

    return department
  }

  async updateDepartment(id: number, updateDepartmentDto: UpdateDepartmentDto) {
    const department = (await this.departmentRepository.getByParams({
      where: { id },
      findOne: true,
    })) as Department

    if (!department) {
      return failureResponse(404, messageKey.data_not_found)
    }

    // Case-insensitive check for name using whereLower
    const isDepartmentExist = await this.checkDepartmentExist(
      updateDepartmentDto.name,
      id,
    )

    if (isDepartmentExist) {
      return failureResponse(400, messageKey.already_exist)
    }

    Object.assign(department, updateDepartmentDto)

    return await this.departmentRepository.save(department)
  }

  async remove(id: number) {
    try {
      const department = (await this.departmentRepository.getByParams({
        where: { id },
        relations: ["team_members", "roles"],
        findOne: true,
      })) as Department

      if (isEmpty(department)) {
        return failureResponse(code.DATA_NOT_FOUND, messageKey.data_not_found)
      }

      // Check if there are team members associated
      if (department.team_members?.length > 0 || department.roles?.length > 0) {
        return failureResponse(
          code.BAD_REQUEST,
          "Cannot delete this department because it has associated team members or roles",
        )
      }

      await this.departmentRepository.remove({ id })

      return successMessage(messageKey.data_removed, { ":data": "department" })
    } catch (error) {
      return failureResponse(code.ERROR, messageKey.something_went_wrong)
    }
  }

  async getDepartmentDropDown() {
    try {
      const result = await this.departmentRepository.getByParams({
        select: ["id", "name"],
        orderBy: { name: "ASC" },
        findOne: false,
      })

      return result
    } catch (error) {
      return failureResponse(500, messageKey.something_went_wrong)
    }
  }
}
