import { Injectable } from "@nestjs/common"
import { CreateVehicleTypeDto } from "../dto/create-vehicle-type.dto"
import { UpdateVehicleTypeDto } from "../dto/update-vehicle-type.dto"
import { VehicleType } from "../entities/vehicle-type.entity"
import { VehicleRepository } from "../repositories/vehicle-type.repository"
import {
  errorMessage,
  isEmpty,
  successMessage,
  validationMessage,
} from "src/utils/helpers"
import { failureResponse, successResponse } from "src/common/response/response"
import { code } from "src/common/response/response.code"
import { messageKey } from "src/constants/message-keys"
import { ConfigService } from "@nestjs/config"
import { InjectRepository } from "@nestjs/typeorm"
import { Repository } from "typeorm"

@Injectable()
export class VehicleTypeService {
  constructor(
    private vehicleTypeRepository: VehicleRepository,
    private readonly configService: ConfigService,
    @InjectRepository(VehicleType)
    private readonly vehicleTypeModelRepository: Repository<VehicleType>,
  ) {}

  async create(createVehicleTypeDto: CreateVehicleTypeDto) {
    if (await this.checkVehicleTypeExits(createVehicleTypeDto.name)) {
      return failureResponse(
        code.VALIDATION,
        validationMessage(messageKey.already_exist, { ":data": "vehicle" }),
      )
    }

    const vehicleType = new VehicleType()
    Object.assign(vehicleType, createVehicleTypeDto)
    await this.vehicleTypeRepository.save(vehicleType)

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

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

    let sortColumn: string
    let order: "ASC" | "DESC" = sortOrder === "ASC" ? "ASC" : "DESC"

    if (sortBy && validSortColumns.includes(sortBy)) {
      sortColumn = sortBy
      order = order || "ASC"
    } else {
      sortColumn = "created_at"
      order = "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", "status"],
    }

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

    const vehicle = await this.vehicleTypeRepository.getByParams(queryParams)

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

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

  async findOne(id: number) {
    const vehicle = await this.vehicleTypeRepository.getByParams({
      where: { id },
      findOne: true,
    })

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

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

  async update(id: number, updateVehicleTypeDto: UpdateVehicleTypeDto) {
    if (await this.checkVehicleTypeExits(updateVehicleTypeDto.name, id)) {
      return failureResponse(
        code.VALIDATION,
        validationMessage(messageKey.already_exist, { ":data": "vehicle" }),
      )
    }

    const vehicle = new VehicleType()

    const condition = {
      id: id,
    }

    Object.assign(vehicle, updateVehicleTypeDto)

    const vehicleType = await this.vehicleTypeRepository.save(
      vehicle,
      condition,
    )

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

  async remove(id: number) {
    try {
      const vehicle: any = await this.vehicleTypeRepository.getByParams({
        where: { id },
        findOne: true,
        relations: ["vehicle_models"],
      })

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

      if (vehicle.vehicle_models?.length > 0) {
        return failureResponse(
          code.BAD_REQUEST,
          "Cannot delete this vehicle type because it has associated vehicle models.",
        )
      }

      await this.vehicleTypeModelRepository.softDelete(id)

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

  async checkVehicleTypeExits(vehicleName: string, excludeId?: number) {
    const whereLikeCondition = {
      name: vehicleName,
    }

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

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

    return !isEmpty(vehicle)
  }

  async getVehicleTypesWithAddOn(
    addOnId?: number,
    limit?: number,
    skip?: number,
  ) {
    const query = this.vehicleTypeModelRepository
      .createQueryBuilder("vehicleType")
      .leftJoinAndSelect("vehicleType.vehicle_models", "vehicleModel")
      .leftJoinAndSelect("vehicleModel.addOns", "addOn")
      .select(["vehicleType.id", "vehicleType.name"])

    if (addOnId) {
      query.andWhere("addOn.id = :addOnId", { addOnId })
    }

    if (limit) {
      query.take(limit)
    }

    if (skip) {
      query.skip(skip)
    }

    const [data, count] = await query.getManyAndCount()

    return {
      success: true,
      code: 200,
      message: "Vehicle types with add-ons retrieved successfully",
      data: {
        count,
        data,
      },
    }
  }
}
