import { Injectable } from "@nestjs/common"
import { ConfigService } from "@nestjs/config"
import { CreateVehicleStatusDto } from "../dto/create-vehicle-status.dto"
import { UpdateVehicleStatusDto } from "../dto/update-vehicle-status.dto"
import { VehicleStatus } from "../entities/vehicle-status.entity"
import { VehicleStatusRepository } from "../repositories/vehicle-status.repository"
import {
  successMessage,
  errorMessage,
  validationMessage,
  isEmpty,
} from "src/utils/helpers"
import { successResponse, failureResponse } from "src/common/response/response"
import { code } from "src/common/response/response.code"
import { messageKey } from "src/constants/message-keys"

@Injectable()
export class VehicleStatusService {
  constructor(
    private vehicleStatusRepository: VehicleStatusRepository,
    private readonly configService: ConfigService,
  ) {}

  async create(createDto: CreateVehicleStatusDto) {
    try {
      if (await this.checkVehicleStatusExists(createDto.name)) {
        return failureResponse(
          code.VALIDATION,
          validationMessage(messageKey.already_exist, {
            ":data": "vehicle status",
          }),
        )
      }

      const status = new VehicleStatus()
      Object.assign(status, createDto)

      await this.vehicleStatusRepository.save(status)

      return successResponse(
        code.SUCCESS,
        successMessage(messageKey.data_add, { ":data": "vehicle status" }),
      )
    } catch (error) {
      return failureResponse(code.ERROR, errorMessage(error))
    }
  }

  async findAll(
    limit,
    skip,
    search?: string,
    sortBy?: string,
    sortOrder?: string,
  ) {
    try {
      const validSortColumns = ["id", "name", "created_at", "updated_at"]

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

      const sortColumn = validSortColumns.includes(sortBy)
        ? sortBy
        : "created_at"
      const order: "ASC" | "DESC" = sortOrder === "ASC" ? "ASC" : "DESC"

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

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

      const result = await this.vehicleStatusRepository.getByParams(queryParams)

      if (isEmpty(result)) {
        return failureResponse(
          code.SUCCESS,
          errorMessage(messageKey.data_not_found, {
            ":data": "vehicle status",
          }),
        )
      }

      return successResponse(
        code.SUCCESS,
        successMessage(messageKey.data_retrieve, { ":data": "vehicle status" }),
        result,
      )
    } catch (error) {
      return failureResponse(code.ERROR, errorMessage(error))
    }
  }

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

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

      return successResponse(
        code.SUCCESS,
        successMessage(messageKey.data_retrieve, { ":data": "vehicle status" }),
        status,
      )
    } catch (error) {
      return failureResponse(code.ERROR, errorMessage(error))
    }
  }

  async update(id: number, updateDto: UpdateVehicleStatusDto) {
    try {
      if (await this.checkVehicleStatusExists(updateDto.name, id)) {
        return failureResponse(
          code.VALIDATION,
          validationMessage(messageKey.already_exist, {
            ":data": "vehicle status",
          }),
        )
      }

      const status = new VehicleStatus()
      Object.assign(status, updateDto)

      const updated = await this.vehicleStatusRepository.save(status, { id })

      return successResponse(
        code.SUCCESS,
        successMessage(messageKey.data_update, { ":data": "vehicle status" }),
        updated,
      )
    } catch (error) {
      return failureResponse(code.ERROR, errorMessage(error))
    }
  }

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

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

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

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

  async checkVehicleStatusExists(name: string, excludeId?: number) {
    try {
      const whereLikeCondition = { name }

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

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

      return !isEmpty(existing)
    } catch (error) {
      return failureResponse(code.ERROR, errorMessage(error))
    }
  }

  async getStatusFromName(name: string): Promise<VehicleStatus> {
    try {
      return (await this.vehicleStatusRepository.getByParams({
        where: { name: { ilike: name } },
        findOne: true,
      })) as VehicleStatus
    } catch (error) {
      null
    }
  }
}
