import { Injectable } from "@nestjs/common"
import { CreateClientCompanyContactDto } from "../dto/create-client-company-contact.dto"
import { UpdateClientCompanyContactDto } from "../dto/update-client-company-contact.dto"
import { ClientCompanyContactRepository } from "../repositories/client-company-contacts.repository"
import { ClientCompanyRepository } from "../../clients-companies/repositories/clients-companies.repository"
import { successResponse, failureResponse } from "src/common/response/response"
import { code } from "src/common/response/response.code"
import {
  errorMessage,
  isEmpty,
  successMessage,
  validationMessage,
} from "src/utils/helpers"
import { messageKey } from "src/constants/message-keys"
import { ClientCompanyContact } from "../entities/client-company-contact.entity"
import { ClientCompanyContactFilterDto } from "../dto/filter-client-company-contact.dto"
import { ConfigService } from "@nestjs/config"

@Injectable()
export class ClientCompanyContactsService {
  constructor(
    private readonly clientCompanyContactsRepository: ClientCompanyContactRepository,
    private readonly clientCompanyRepository: ClientCompanyRepository,
    private readonly configService: ConfigService,
  ) {}

  async create(createClientCompanyContactDto: CreateClientCompanyContactDto) {
    const isCompanyExist = await this.clientCompanyRepository.getByParams({
      where: {
        id: createClientCompanyContactDto.client_company_id,
      },
      findOne: true,
    })

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

    const isContactExist =
      await this.clientCompanyContactsRepository.getByParams({
        where: {
          phone_number: createClientCompanyContactDto.phone_number,
          client_company_id: createClientCompanyContactDto.client_company_id,
        },
        findOne: true,
      })

    if (!isEmpty(isContactExist)) {
      return failureResponse(
        code.VALIDATION,
        validationMessage(messageKey.already_exist, {
          ":data": "Contact number",
        }),
      )
    }

    const isEmailExist = await this.clientCompanyContactsRepository.getByParams(
      {
        where: {
          client_company_id: createClientCompanyContactDto.client_company_id,
          email: createClientCompanyContactDto.email,
        },
        findOne: true,
      },
    )

    if (!isEmpty(isEmailExist)) {
      return failureResponse(
        code.VALIDATION,
        validationMessage(messageKey.already_exist, { ":data": "Email" }),
      )
    }

    const clientCompanyContact = new ClientCompanyContact()

    Object.assign(clientCompanyContact, createClientCompanyContactDto)

    const createdContact =
      await this.clientCompanyContactsRepository.save(clientCompanyContact)

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

  async findAll(filter: ClientCompanyContactFilterDto) {
    const defaultPagination = {
      take: this.configService.get<number>("APP.pagination.take"),
      skip: this.configService.get<number>("APP.pagination.skip"),
    }
    const { search, limit, skip, client_company_id } = filter || {}

    const where: any = {}

    if (client_company_id) {
      where.client_company_id = client_company_id
    }

    // Build search object for all relevant fields
    let searchObj: any = {}
    if (search) {
      searchObj = {
        first_name: search,
        last_name: search,
        email: search,
        phone_number: search,
        position: search,
        "entity_client_company.company_name": search,
      }
    }

    const params: any = {
      take: Number(limit) || defaultPagination.take,
      skip: Number(skip) || defaultPagination.skip,
      orderBy: { created_at: "DESC" },
      where,
      search: searchObj,
      innerJoinRelations: ["client_company:id,company_name,deleted_at"],
      select: [
        "id",
        "client_company_id",
        "first_name",
        "last_name",
        "email",
        "country_code",
        "phone_number",
        "position",
        "status",
        "created_at",
        "updated_at",
      ],
    }

    const contacts =
      await this.clientCompanyContactsRepository.getByParams(params)

    return successResponse(
      code.SUCCESS,
      successMessage(messageKey.data_retrieve, {
        ":data": "Client Company Contacts",
      }),
      contacts,
    )
  }

  async findOne(id: number) {
    const contact = await this.clientCompanyContactsRepository.getByParams({
      where: { id },
      findOne: true,
      relations: ["client_company:id,company_name"],
      select: [
        "id",
        "client_company_id",
        "first_name",
        "last_name",
        "email",
        "country_code",
        "phone_number",
        "position",
        "status",
        "created_at",
        "updated_at",
      ],
    })

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

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

  async update(
    id: number,
    updateClientCompanyContactDto: UpdateClientCompanyContactDto,
  ) {
    const clientContact =
      await this.clientCompanyContactsRepository.getByParams({
        where: { id },
        findOne: true,
      })

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

    const isCompanyExist = await this.clientCompanyRepository.getByParams({
      where: { id: updateClientCompanyContactDto?.client_company_id },
      findOne: true,
    })

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

    const isEmailExist = await this.clientCompanyContactsRepository.getByParams(
      {
        where: {
          email: updateClientCompanyContactDto.email,
          client_company_id: updateClientCompanyContactDto?.client_company_id,
          id: { not: id },
        },
        findOne: true,
      },
    )

    if (!isEmpty(isEmailExist)) {
      return failureResponse(
        code.VALIDATION,
        validationMessage(messageKey.already_exist, { ":data": "Email" }),
      )
    }

    const isContactExist =
      await this.clientCompanyContactsRepository.getByParams({
        where: {
          client_company_id: updateClientCompanyContactDto?.client_company_id,
          phone_number: updateClientCompanyContactDto?.phone_number,
          id: { not: id },
        },
        findOne: true,
      })

    if (!isEmpty(isContactExist)) {
      return failureResponse(
        code.VALIDATION,
        validationMessage(messageKey.already_exist, { ":data": "Contact" }),
      )
    }

    const clientContactEntity = new ClientCompanyContact()

    Object.assign(clientContactEntity, updateClientCompanyContactDto)

    const updated = await this.clientCompanyContactsRepository.save(
      clientContactEntity,
      {
        id,
      },
    )

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

  async remove(id: number) {
    const contact = (await this.clientCompanyContactsRepository.getByParams({
      where: { id },
      findOne: true,
    })) as ClientCompanyContact

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

    await this.clientCompanyContactsRepository.remove({ id })

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