import { Injectable } from "@nestjs/common"
import { StateRepository } from "../repositories/state.repository"
import { CreateStateDto } from "../dto/create-state.dto"
import { isEmpty, successMessage } from "src/utils/helpers"
import { failureResponse } from "src/common/response/response"
import { messageKey } from "src/constants/message-keys"
import { FindAllStateDto } from "../dto/find-all-state.dto"
import { State } from "../entities/state.entity"
import { UpdateStateDto } from "../dto/update-state.dto"
import { InjectRepository } from "@nestjs/typeorm"
import { Repository } from "typeorm"
import { code } from "src/common/response/response.code"

@Injectable()
export class StateService {
  constructor(
    private readonly stateRepository: StateRepository,
    @InjectRepository(State)
    private readonly stateModelRepository: Repository<State>,
  ) {}

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

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

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

    return !isEmpty(currency)
  }

  async createstate(createStateDto: CreateStateDto) {
    const isstateExist = await this.checkstateExist(createStateDto.name)

    if (isstateExist) {
      return failureResponse(400, messageKey.already_exist)
    }
    try {
      const result = await this.stateRepository.save({
        name: createStateDto.name,
        country_id: createStateDto.country_id,
      })

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

  async findAllstate(params: FindAllStateDto) {
    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 filters: any = {}

    if (params?.country_id) {
      filters["country_id"] = params.country_id.split(",")
    }

    const state = await this.stateRepository.getByParams({
      search: {
        name: params.search,
      },
      whereIn: filters,
      take: Number(params.limit),
      skip: Number(params.skip),
      orderBy: {
        [sortColumn]: sortOrder,
      },
      relations: [
        "country:id,name",
        "cities:id,name",
        "team_member:id,first_name,last_name.role:id,name",
      ],
    })

    return {
      success: true,
      code: 200,
      message: messageKey.data_retrieve,
      data: state,
    }
  }

  async findOneState(id: number): Promise<State> {
    const state = (await this.stateRepository.getByParams({
      where: { id },
      findOne: true,
      relations: ["country"],
    })) as State

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

    return state
  }

  async updateState(id: number, updateStateDto: UpdateStateDto) {
    const state = (await this.stateRepository.getByParams({
      where: { id },
      findOne: true,
    })) as State

    if (!state) {
      return failureResponse(404, messageKey.data_not_found)
    }
    const isstateExist = await this.checkstateExist(updateStateDto.name, id)

    if (isstateExist) {
      return failureResponse(400, messageKey.already_exist)
    }
    Object.assign(state, updateStateDto)

    return await this.stateRepository.save(state)
  }

  async remove(id: number) {
    try {
      const state = (await this.stateRepository.getByParams({
        where: { id },
        relations: ["cities"],
        findOne: true,
      })) as State

      if (!state) {
        return failureResponse(code.DATA_NOT_FOUND, messageKey.data_not_found)
      }

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

      await this.stateModelRepository.softDelete(id)

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

  async getStatesByCountry(country_id: number) {
    const states = await this.stateRepository.findByCountryId(country_id)

    if (!states || states.length === 0) {
      return failureResponse(404, messageKey.data_not_found)
    }

    return {
      success: true,
      code: 200,
      message: messageKey.data_retrieve,
      data: states,
    }
  }
}
