import { Injectable } from "@nestjs/common"
import { CreateEscortDto } from "../dto/create-escort.dto"
import { UpdateEscortDto } from "../dto/update-escort.dto"
import { EscortRepository } from "../repositories/escort.repository"
import { UpsertEscortDto } from "../dto/bulk-escort.dto"
import { CustomerRepository } from "../../customers/repositories/customers.repository"
import { failureResponse, successResponse } from "src/common/response/response"
import { code } from "src/common/response/response.code"
import { errorMessage, isEmpty, successMessage } from "src/utils/helpers"
import { messageKey } from "src/constants/message-keys"
import { Escort } from "../entities/escort.entity"
import { ConfigService } from "@nestjs/config"
import { FilterEscortDto } from "../dto/filter-escort.dto"

@Injectable()
export class EscortsService {
  constructor(
    private readonly escortRepository: EscortRepository,
    private readonly customerRepository: CustomerRepository,
    private readonly configService: ConfigService,
  ) {}

  async create(createEscortDto: CreateEscortDto) {
    const customer = await this.customerRepository.getByParams({
      where: { id: createEscortDto?.customer_id },
      findOne: true,
    })

    if (isEmpty(customer)) {
      return failureResponse(
        code.VALIDATION,
        errorMessage(messageKey.data_not_found, {
          ":data": "Customer",
        }),
      )
    }
    const escort: any = new Escort()

    Object.assign(escort, createEscortDto)

    await this.escortRepository.save(escort)

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

  async findAllEscort() {
    const escort = await this.escortRepository.getByParams({})

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

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

    const search: any = {}
    if (filterEscortDto.search) {
      search.name = filterEscortDto.search
      search.email = filterEscortDto.search
      search.phone_number = filterEscortDto.search
    }

    const filters: any = {}
    if (filterEscortDto?.customer_id) {
      filters["customer_id"] = filterEscortDto.customer_id.split(",")
    }

    const queryParams: any = {
      take: filterEscortDto?.limit || defaultPagination.take,
      skip: filterEscortDto?.skip || defaultPagination.skip,
      search,
      whereIn: filters,
      orderBy: { created_at: "DESC" },
      select: [
        "id",
        "name",
        "relation",
        "gender",
        "date_of_birth",
        "passport_number",
        "country_code",
        "phone_number",
        "email",
        "escort_type",
        "is_sponsered",
        "created_at",
      ],
    }

    const escort = await this.escortRepository.getByParams(queryParams)

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

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

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

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

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

  async upsertCustomerEscorts(upsertDto: UpsertEscortDto) {
    const customer = await this.customerRepository.getByParams({
      where: { id: upsertDto?.customer_id },
      findOne: true,
    })

    if (isEmpty(customer)) {
      return failureResponse(
        code.VALIDATION,
        errorMessage(messageKey.data_not_found, {
          ":data": "Customer",
        }),
      )
    }

    for (const escortData of upsertDto?.escorts) {
      if (escortData?.escort_id && escortData?.should_remove) {
        await this.escortRepository.remove(
          { id: Number(escortData?.escort_id) },
          null,
          false,
        )
      } else if (escortData?.escort_id) {
        // eslint-disable-next-line @typescript-eslint/no-unused-vars
        const { escort_id, should_remove, ...escortPayload } = escortData

        const condition: any = { id: escort_id }
        const escort = new Escort()

        Object.assign(escort, escortPayload)

        await this.escortRepository.save(escort, condition)
      } else {
        const escort = new Escort()
        Object.assign(escort, escortData)

        await this.escortRepository.save(escort)
      }
    }

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

  async update(id: number, updateEscortDto: UpdateEscortDto) {
    const customer = await this.customerRepository.getByParams({
      where: { id: updateEscortDto?.customer_id },
      findOne: true,
    })

    if (isEmpty(customer)) {
      return failureResponse(
        code.VALIDATION,
        errorMessage(messageKey.data_not_found, {
          ":data": "Customer",
        }),
      )
    }

    const escortData = await this.escortRepository.getByParams({
      where: {
        id: id,
      },
      findOne: true,
    })

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

    const escort = new Escort()

    Object.assign(escort, updateEscortDto)

    await this.escortRepository.save(escort, { id: id })

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

  async remove(id: number) {
    const escortData = await this.escortRepository.getByParams({
      where: {
        id: id,
      },
      findOne: true,
    })

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

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

    return successResponse(
      code.SUCCESS,
      successMessage(messageKey.data_removed, { ":data": "Escort" }),
    )
  }

  async getEscortTypes() {
    const escortTypes = [
      "Official",
      "Unofficial",
      "Medical",
      "Donor",
      "Sibling",
    ]

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