import { Injectable } from "@nestjs/common"
import { failureResponse, successResponse } from "src/common/response/response"
import { code } from "src/common/response/response.code"
import { messageKey } from "src/constants/message-keys"
import { messages } from "src/constants/messages"
import { isEmpty } from "src/utils/helpers"
import { CreateModuleDto } from "../dto/create-module.dto"
import { FindAllModuleDto } from "../dto/find-all-module.dto"
import { UpdateModuleDto } from "../dto/update-module.dto"
import { Modules } from "../entities/module.entity"
import { ModuleRepository } from "../repositories/module.repository"

@Injectable()
export class ModuleService {
  constructor(private readonly moduleRepository: ModuleRepository) {}

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

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

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

    return !isEmpty(currency)
  }

  async createModule(createModuleDto: CreateModuleDto) {
    const isModuleExist = await this.checkModuleExist(
      createModuleDto.module_name,
      createModuleDto.module_type,
    )

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

    try {
      const result = await this.moduleRepository.save({
        module_name: createModuleDto.module_name,
        module_type: createModuleDto.module_type,
      })

      return successResponse(code.CREATED, messages.success.data_add, result)
    } catch (error) {
      return failureResponse(code.ERROR, messageKey.something_went_wrong)
    }
  }

  async findAllModules(params: FindAllModuleDto) {
    const validSortColumns = [
      "id",
      "module_name",
      "module_type",
      "module_access",
      "created_at",
      "updated_at",
    ]

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

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

    const modules = await this.moduleRepository.getByParams({
      search: {
        module_name: params.search,
      },
      where: {
        module_access: true,
      },
      orderBy: {
        [sortColumn]: sortOrder,
      },
      select: [
        "id",
        "module_name",
        "module_type",
        "module_access",
        "created_at",
      ],
    })

    return modules
  }

  async findOneModule(id: number): Promise<Modules> {
    const module = (await this.moduleRepository.getByParams({
      where: { id },
      findOne: true,
    })) as Modules

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

    return module
  }

  async updateModule(id: number, updateModuleDto: UpdateModuleDto) {
    const module = (await this.moduleRepository.getByParams({
      where: { id },
      relations: ["business_verticals"],
      findOne: true,
    })) as Modules

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

    const isModuleExist = await this.checkModuleExist(
      updateModuleDto.module_name,
      updateModuleDto.module_type,
      id,
    )

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

    try {
      const result = await this.moduleRepository.save({
        ...module,
        module_name: updateModuleDto.module_name,
        module_type: updateModuleDto.module_type,
        module_access: updateModuleDto.module_access,
      })

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

  async remove(id: number) {
    const module = await this.moduleRepository.getByParams({
      where: { id },
      findOne: true,
    })

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

    await this.moduleRepository.remove({ id })

    return successResponse(code.SUCCESS, messages.success.data_removed)
  }

  async getDropdownModules() {
    const modules = await this.moduleRepository.getByParams({
      select: ["id", "module_name", "module_type", "module_access"],
      orderBy: { module_name: "ASC" },
    })

    return modules
  }

  // Service method
  async getModulesByBusinessVerticalIds(business_vertical_ids: number[]) {
    try {
      const modules =
        await this.moduleRepository.getModulesByBusinessVerticalIds(
          business_vertical_ids,
        )

      if (isEmpty(modules)) {
        return failureResponse(code.BAD_REQUEST, messageKey.data_not_found)
      }

      return modules
    } catch (error) {
      return failureResponse(code.ERROR, messageKey.something_went_wrong)
    }
  }
}
