import { Injectable } from "@nestjs/common"
import { ConfigService } from "@nestjs/config"
import { failureResponse, successResponse } from "src/common/response/response"
import { code } from "src/common/response/response.code"
import { messageKey } from "src/constants/message-keys"
import {
  errorMessage,
  isEmpty,
  successMessage,
  validationMessage,
} from "src/utils/helpers"
import { CreateClientTypeDto } from "../dto/create-client-type.dto"
import { ClientType } from "../entities/client-type.entity"
import { ClientTypeRepository } from "../repositories/client-type.repository"
import { UpdateClientTypeDto } from "../dto/update-clinet-type.dto"

@Injectable()
export class ClientTypeService {
  constructor(
    private clientTypeRepository: ClientTypeRepository,
    private readonly configService: ConfigService,
  ) {}

  async create(dto: CreateClientTypeDto) {
    if (await this.checkClientTypeExists(dto.name)) {
      return failureResponse(
        code.VALIDATION,
        validationMessage(messageKey.already_exist, {
          ":data": "client type",
        }),
      )
    }

    const entity = new ClientType()
    Object.assign(entity, dto)
    await this.clientTypeRepository.save(entity)

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

  async findAll(
    limit?: string,
    skip?: string,
    search?: string,
    sortBy?: string,
    sortOrder?: string,
  ) {
    try {
      const validSortColumns = ["id", "name", "created_at", "updated_at"]
      const sortColumn = validSortColumns.includes(sortBy)
        ? sortBy
        : "created_at"
      const order: "ASC" | "DESC" = sortOrder === "ASC" ? "ASC" : "DESC"

      const defaultPagination = {
        take: this.configService.get("APP.pagination.take"),
        skip: this.configService.get("APP.pagination.skip"),
      }

      const queryParams: any = {
        take: limit || defaultPagination.take,
        skip: skip || defaultPagination.skip,
        orderBy: { [sortColumn]: order },
        select: ["id", "name", "description"],
      }

      if (search) {
        queryParams.where = {
          ...queryParams.where,
          name: { ilike: search },
        }
      }

      const data = await this.clientTypeRepository.getByParams(queryParams)

      if (isEmpty(data)) {
        return failureResponse(
          code.SUCCESS,
          errorMessage(messageKey.data_not_found, {
            ":data": "client type",
          }),
        )
      }

      return successResponse(
        code.SUCCESS,
        successMessage(messageKey.data_retrieve, {
          ":data": "client type",
        }),
        data,
      )
    } catch (error) {
      return failureResponse(code.ERROR, messageKey.something_went_wrong)
    }
  }

  async findOne(id: number) {
    try {
      const data = await this.clientTypeRepository.getByParams({
        where: { id },
        findOne: true,
      })

      if (isEmpty(data)) {
        return failureResponse(
          code.SUCCESS,
          errorMessage(messageKey.data_not_found, {
            ":data": "client type",
          }),
        )
      }

      return successResponse(
        code.SUCCESS,
        successMessage(messageKey.data_retrieve, {
          ":data": "client type",
        }),
        data,
      )
    } catch (error) {
      return failureResponse(code.ERROR, messageKey.something_went_wrong)
    }
  }

  async update(id: number, dto: UpdateClientTypeDto) {
    try {
      if (await this.checkClientTypeExists(dto.name, id)) {
        return failureResponse(
          code.VALIDATION,
          validationMessage(messageKey.already_exist, {
            ":data": "client type",
          }),
        )
      }

      const entity = new ClientType()
      Object.assign(entity, dto)

      const updated = await this.clientTypeRepository.save(entity, { id })

      return successResponse(
        code.SUCCESS,
        successMessage(messageKey.data_update, {
          ":data": "client type",
        }),
        updated,
      )
    } catch (error) {
      return failureResponse(code.ERROR, messageKey.something_went_wrong)
    }
  }

  async remove(id: number) {
    try {
      const status = await this.clientTypeRepository.getByParams({
        where: { id },
        findOne: true,
      })

      if (isEmpty(status)) {
        return failureResponse(
          code.DATA_NOT_FOUND,
          errorMessage(messageKey.data_not_found, {
            ":data": "client type",
          }),
        )
      }

      await this.clientTypeRepository.remove({ id }, null, false)

      return successResponse(
        code.SUCCESS,
        successMessage(messageKey.data_removed, {
          ":data": "client type",
        }),
      )
    } catch (error) {
      return failureResponse(code.ERROR, errorMessage(error))
    }
  }

  async checkClientTypeExists(name: string, excludeId?: number) {
    const whereLikeCondition = { name }
    const whereCondition: any = {}

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

    const existing = await this.clientTypeRepository.getByParams({
      where: whereCondition,
      whereLower: whereLikeCondition,
      findOne: true,
    })

    return !isEmpty(existing)
  }
}
