import { Injectable } from "@nestjs/common"
import { failureResponse } from "src/common/response/response"
import { isEmpty, successMessage } from "src/utils/helpers"
import { messageKey } from "src/constants/message-keys"
import { CountryRepository } from "../repositories/country.repository"
import { CreateCountryDto } from "../dto/create-country.dto"
import { Country } from "../entities/country.entity"
import { UpdateCountryDto } from "../dto/update-country.dto"
import { FindAllCountryDto } from "../dto/find-all-country.dto"
import { InjectRepository } from "@nestjs/typeorm"
import { Repository } from "typeorm"
import { code } from "src/common/response/response.code"

@Injectable()
export class CountryService {
  constructor(
    private readonly countryRepository: CountryRepository,
    @InjectRepository(Country)
    private readonly countryModelRepository: Repository<Country>,
  ) {}

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

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

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

    return !isEmpty(currency)
  }

  async createCountry(createCountryDto: CreateCountryDto) {
    const isCountryExist = await this.checkCountryExist(createCountryDto.name)

    if (isCountryExist) {
      return failureResponse(400, messageKey.already_exist)
    }
    try {
      const result = await this.countryRepository.save({
        name: createCountryDto.name,
      })

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

  async findAllCountries(params: FindAllCountryDto) {
    const validSortColumns = ["id", "name", "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 = "DESC"
    }

    const countries = await this.countryRepository.getByParams({
      search: {
        name: params.search,
      },
      take: Number(params.limit),
      skip: Number(params.skip),
      orderBy: {
        [sortColumn]: sortOrder,
      },
    })

    return countries
  }

  async findOneCountry(id: number): Promise<Country> {
    const country = (await this.countryRepository.getByParams({
      where: { id },
      findOne: true,
    })) as Country

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

    return country
  }

  async updateCountry(id: number, updateCountryDto: UpdateCountryDto) {
    const country = (await this.countryRepository.getByParams({
      where: { id },
      findOne: true,
    })) as Country

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

    const isCountryExist = await this.checkCountryExist(
      updateCountryDto.name,
      id,
    )

    if (isCountryExist) {
      return failureResponse(400, messageKey.already_exist)
    }
    Object.assign(country, updateCountryDto)

    return await this.countryRepository.save(country)
  }

  async remove(id: number) {
    try {
      const country = (await this.countryRepository.getByParams({
        where: { id },
        findOne: true,
        relations: ["states", "cities", "currencies"],
      })) as Country

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

      if (
        country.states?.length > 0 ||
        country.cities?.length > 0 ||
        country.currencies?.length > 0
      ) {
        return failureResponse(
          code.BAD_REQUEST,
          "Cannot delete this country because it has associated cities,states or currencies",
        )
      }

      await this.countryModelRepository.softDelete(id)

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

  async getDropdownCountries() {
    const countries = await this.countryRepository.getByParams({
      select: ["id", "name"],
      orderBy: { name: "ASC" },
      relations: ["states:id,name.cities:id,name"],
    })

    return countries
  }
}
