import { Injectable } from "@nestjs/common"
import { PermissionRepository } from "./repositories/permission.repository"
import { Permission } from "./entities/permission.entity"
import { verifyJwtToken } from "src/utils/jwt"
import { failureResponse, successResponse } from "src/common/response/response"
import { code } from "src/common/response/response.code"
import {
  errorMessage,
  isEmpty,
  successMessage,
  validationMessage,
} from "src/utils/helpers"
import { messageKey } from "src/constants/message-keys"
import { CreatePermissionDto } from "./dto/create-permission.dto"
import { UpdatePermissionDto } from "./dto/update-permission.dto"
import { getPermissionsByGroup } from "src/constants/permissions.constant"

@Injectable()
export class PermissionsService {
  constructor(private readonly permissionRepository: PermissionRepository) {}

  async create(createPermissionDto: CreatePermissionDto, token: string) {
    const decoded = verifyJwtToken(token)

    if (!decoded) {
      return failureResponse(
        code.VALIDATION,
        validationMessage(messageKey.invalid_token),
      )
    }

    // Check if permission with same group_key and permission_key exists
    const existingPermission = await this.permissionRepository.getByParams({
      where: {
        group_key: createPermissionDto.group_key,
        permission_key: createPermissionDto.permission_key,
      },
      whereNull: ["deleted_at"],
      findOne: true,
    })

    if (existingPermission) {
      return failureResponse(
        code.VALIDATION,
        validationMessage(messageKey.already_exist, {
          ":data": "Permission",
          ":field": "combination",
        }),
      )
    }

    let permission: any = new Permission()
    permission = {
      ...createPermissionDto,
      status: createPermissionDto.status || 1,
      created_by: decoded.user_id,
    }

    await this.permissionRepository.save(permission)

    return successResponse(
      code.SUCCESS,
      successMessage(messageKey.data_add, { ":data": "Permission" }),
    )
  }

  async findAll(query: any = {}, isCompanyAdmin: boolean = false) {
    const { search, status, group_key, is_company_admin } = query

    const whereConditions: any = {}
    const searchConditions: any = {}

    // Add filters
    if (group_key) {
      whereConditions.group_key = group_key
    }

    if (status !== undefined && status !== null) {
      whereConditions.status = status
    }

    // Add search functionality
    if (search) {
      searchConditions.label = search
      searchConditions.permission_key = search
    }

    const whereNotIn: any = []

    if (isCompanyAdmin || is_company_admin == "true") {
      whereNotIn.push("view_company", "manage_company")
    }

    const permissions: any = await this.permissionRepository.getByParams({
      where: whereConditions,
      whereNotIn: { permission_key: whereNotIn },
      search: !isEmpty(searchConditions) ? searchConditions : undefined,
      whereNull: ["deleted_at"],
      orderBy: { group_key: "ASC", permission_key: "ASC" },
    })

    return successResponse(
      code.SUCCESS,
      successMessage(messageKey.data_retrieve, { ":data": "Permissions" }),
      permissions,
    )
  }

  async findOne(id: number) {
    const permission: any = await this.permissionRepository.getByParams({
      where: { id },
      whereNull: ["deleted_at"],
      findOne: true,
    })

    if (isEmpty(permission)) {
      return failureResponse(
        code.VALIDATION,
        errorMessage(messageKey.data_not_found, { ":data": "Permission" }),
      )
    }

    return successResponse(
      code.SUCCESS,
      successMessage(messageKey.data_retrieve, { ":data": "Permission" }),
      permission,
    )
  }

  async update(
    id: number,
    updatePermissionDto: UpdatePermissionDto,
    token: string,
  ) {
    const decoded = verifyJwtToken(token)

    if (!decoded) {
      return failureResponse(
        code.VALIDATION,
        validationMessage(messageKey.invalid_token),
      )
    }

    const permission: any = await this.permissionRepository.getByParams({
      where: { id },
      whereNull: ["deleted_at"],
      findOne: true,
    })

    if (isEmpty(permission)) {
      return failureResponse(
        code.VALIDATION,
        errorMessage(messageKey.data_not_found, { ":data": "Permission" }),
      )
    }

    // Check if permission with same group_key and permission_key exists (excluding current record)
    if (updatePermissionDto.group_key && updatePermissionDto.permission_key) {
      const existingPermission = await this.permissionRepository.getByParams({
        where: {
          group_key: updatePermissionDto.group_key,
          permission_key: updatePermissionDto.permission_key,
        },
        whereNull: ["deleted_at"],
        whereNotIn: { id: [id] },
        findOne: true,
      })

      if (existingPermission) {
        return failureResponse(
          code.VALIDATION,
          validationMessage(messageKey.already_exist, {
            ":data": "Permission",
            ":field": "combination",
          }),
        )
      }
    }

    // Update the permission
    Object.assign(permission, updatePermissionDto)
    permission.updated_by = decoded.user_id
    await this.permissionRepository.save(permission)

    return successResponse(
      code.SUCCESS,
      successMessage(messageKey.data_update, { ":data": "Permission" }),
    )
  }

  async remove(id: number, token: string) {
    const decoded = verifyJwtToken(token)

    if (!decoded) {
      return failureResponse(
        code.VALIDATION,
        validationMessage(messageKey.invalid_token),
      )
    }

    const permission: any = await this.permissionRepository.getByParams({
      where: { id },
      whereNull: ["deleted_at"],
      findOne: true,
    })

    if (isEmpty(permission)) {
      return failureResponse(
        code.VALIDATION,
        errorMessage(messageKey.data_not_found, { ":data": "Permission" }),
      )
    }

    await this.permissionRepository.remove({ id: permission.id })

    await this.permissionRepository.save({
      id: permission.id,
      deleted_by: decoded.user_id,
    })

    return successResponse(
      code.SUCCESS,
      successMessage(messageKey.data_removed, { ":data": "Permission" }),
    )
  }

  async getGroupedPermissions() {
    const permissions: any = await this.permissionRepository.getByParams({
      where: { status: 1 },
      whereNull: ["deleted_at"],
      orderBy: { group_key: "ASC", permission_key: "ASC" },
    })

    if (isEmpty(permissions)) {
      return successResponse(
        code.SUCCESS,
        successMessage(messageKey.data_retrieve, { ":data": "Permissions" }),
        getPermissionsByGroup() as any,
      )
    }

    const permissionsList = Array.isArray(permissions)
      ? permissions
      : [permissions]
    const groupedPermissions: Record<string, any[]> = {}

    permissionsList.forEach((permission: any) => {
      if (!groupedPermissions[permission.group_key]) {
        groupedPermissions[permission.group_key] = []
      }
      groupedPermissions[permission.group_key].push({
        id: permission.id,
        permission_key: permission.permission_key,
        label: permission.label,
        description: permission.description,
      })
    })

    return successResponse(
      code.SUCCESS,
      successMessage(messageKey.data_retrieve, { ":data": "Permissions" }),
      groupedPermissions as any,
    )
  }

  async activeInactive(id: number, token: string) {
    const decoded = verifyJwtToken(token)

    if (!decoded) {
      return failureResponse(
        code.VALIDATION,
        validationMessage(messageKey.invalid_token),
      )
    }

    const permission: any = await this.permissionRepository.getByParams({
      where: { id },
      findOne: true,
    })

    if (isEmpty(permission)) {
      return failureResponse(
        code.VALIDATION,
        errorMessage(messageKey.data_not_found, { ":data": "Permission" }),
      )
    }

    permission.status = permission.status === 1 ? 0 : 1
    permission.updated_by = decoded.user_id

    await this.permissionRepository.save(permission)

    return successResponse(
      code.SUCCESS,
      successMessage(messageKey.status_change, { ":data": "Permission" }),
    )
  }

  async checkPermissionExist(groupKey: string, permissionKey: string) {
    const permission = await this.permissionRepository.getByParams({
      where: {
        group_key: groupKey,
        permission_key: permissionKey,
      },
      whereNull: ["deleted_at"],
      findOne: true,
    })

    return !isEmpty(permission)
  }

  async findByPermissionKey(permissionKey: string) {
    const permission = await this.permissionRepository.getByParams({
      where: {
        permission_key: permissionKey,
      },
      whereNull: ["deleted_at"],
      findOne: true,
    })

    return permission
  }
}
