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 { CreateContractCoverageDto } from "../dto/create-contract-coverage.dto"
import { UpdateContractCoverageDto } from "../dto/update-contract-coverage.dto"
import { ContractCoverage } from "../entities/contract-coverage.entity"
import { ContractCoverageRepository } from "../repositories/contract-coverage.repository"

@Injectable()
export class ContractCoverageService {
  constructor(
    private contractCoverageRepository: ContractCoverageRepository,
    private readonly configService: ConfigService,
  ) {}

  async create(dto: CreateContractCoverageDto) {
    if (await this.checkContractCoverageExists(dto.name)) {
      return failureResponse(
        code.VALIDATION,
        validationMessage(messageKey.already_exist, {
          ":data": "contract coverage",
        }),
      )
    }

    const entity = new ContractCoverage()
    Object.assign(entity, dto)
    await this.contractCoverageRepository.save(entity)

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

  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.contractCoverageRepository.getByParams(queryParams)

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

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

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

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

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

  async update(id: number, dto: UpdateContractCoverageDto) {
    try {
      if (await this.checkContractCoverageExists(dto.name, id)) {
        return failureResponse(
          code.VALIDATION,
          validationMessage(messageKey.already_exist, {
            ":data": "contract coverage",
          }),
        )
      }

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

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

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

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

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

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

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

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

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

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

    return !isEmpty(existing)
  }
}
