import httpStatus from 'http-status';
import { FilterQuery } from 'mongoose';

import State from '@/modules/master/location/state/state.model.js';
import ApiError from '@/shared/utils/errors/ApiError.js';
import { IState } from '@/modules/master/location/location.interfaces.js';
import pick from '@/shared/utils/pick.js';
import { getObjectId } from '@/shared/utils/commonHelper';
import responseCodes from '@/shared/utils/responseCode/responseCode';
import { defaultStatus } from '@/shared/utils/responseCode/httpStatusAlias';
import { safeDeleteById } from '@/shared/utils/guard/ref-guard';

const { StateResponseCodes } = responseCodes;

export const create = async (data: Partial<IState>): Promise<IState> => {
  const { name, country, loc } = data;

  const existing = await State.findOne({
    name,
    country,
    'loc.coordinates': loc?.coordinates,
  });

  if (existing)
    throw new ApiError(
      defaultStatus.BAD_REQUEST,
      'State with this name and coordinates already exists.',
      true,
      '',
      StateResponseCodes.STATE_ALREADY_EXISTS,
    );

  return await State.create(data);
};

export const getById = async (id: string): Promise<IState> => {
  const state = await State.findById(id);
  if (!state) throw new ApiError(httpStatus.NOT_FOUND, 'State not found');
  return state;
};

export const update = async (
  id: string,
  data: Partial<IState>,
): Promise<IState> => {
  const state = await State.findByIdAndUpdate(id, data, {
    new: true,
    runValidators: true,
  });
  if (!state) throw new ApiError(httpStatus.NOT_FOUND, 'State not found');
  return state;
};

export const remove = async (id: string): Promise<boolean> => {
  await safeDeleteById(State, id, StateResponseCodes.STATE_IN_USE);
  return true;
};

export const list = async (query: Record<string, unknown>) => {
  const filter = pick(query, ['search', 'country']);

  const options = pick(query, [
    'sortBy',
    'limit',
    'page',
    'populate',
    'fields',
  ]);
  let queryFilter: FilterQuery<IState> = {
    ...(filter.country && { country: getObjectId(filter.country) }),
  };

  if (filter.search)
    queryFilter.$or = [{ name: { $regex: filter.search, $options: 'i' } }];

  return await State.paginate(queryFilter, options);
};
