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

import SubCategory from '@/modules/master/property/subCategory/subCategory.model';
import {
  IPropertyFilter,
  ISubCategory,
} from '@/modules/master/property/property.interfaces';
import ApiError from '@/shared/utils/errors/ApiError';
import { PaginateOptions } from '@/shared/utils/plugins/paginate/paginate';
import { defaultStatus } from '@/shared/utils/responseCode/httpStatusAlias';
import responseCodes from '@/shared/utils/responseCode/responseCode';
import { safeDeleteById } from '@/shared/utils/guard/ref-guard';
import { getObjectId } from '@/shared/utils/commonHelper';
const { SubCategoryResponseCodes } = responseCodes;

export const create = async (body: ISubCategory): Promise<ISubCategory> => {
  const { name, categoryId } = body;

  const existing = await SubCategory.findOne({
    name: name?.toLowerCase().trim(),
    categoryId,
  });

  if (existing)
    throw new ApiError(
      defaultStatus.BAD_REQUEST,
      'Sub-category with this name already exists under the same category.',
      true,
      '',
      SubCategoryResponseCodes.SUBCATEGORY_ALREADY_EXISTS,
    );

  return await SubCategory.create(body);
};

export const getById = async (id: string): Promise<ISubCategory> => {
  const subCategory = await SubCategory.findById(id);
  if (!subCategory)
    throw new ApiError(httpStatus.NOT_FOUND, 'SubCategory not found');

  return subCategory;
};

export const update = async (
  id: string,
  body: Partial<ISubCategory>,
): Promise<ISubCategory> => {
  const { name, categoryId } = body;

  if (name || categoryId) {
    const existing = await SubCategory.findOne({
      _id: { $ne: id },
      name: name?.toLowerCase().trim(),
      categoryId: categoryId ?? (await SubCategory.findById(id))?.categoryId,
    });

    if (existing)
      throw new ApiError(
        defaultStatus.BAD_REQUEST,
        'Sub-category with this name already exists under the same category.',
        true,
        '',
        SubCategoryResponseCodes.SUBCATEGORY_ALREADY_EXISTS,
      );
  }

  const subCategory = await SubCategory.findByIdAndUpdate(id, body, {
    new: true,
    runValidators: true,
  });
  if (!subCategory)
    throw new ApiError(httpStatus.NOT_FOUND, 'SubCategory not found');

  return subCategory;
};

export const remove = async (id: string): Promise<boolean> => {
  await safeDeleteById(
    SubCategory,
    id,
    SubCategoryResponseCodes.SUBCATEGORY_IN_USE,
  );

  return true;
};

export const list = (query: Record<string, unknown>): Promise<ISubCategory[]> =>
  SubCategory.find(query);

export const querySubCategory = async (
  filter: IPropertyFilter = {},
  options: PaginateOptions = {},
) => {
  const { search, categoryId, ...restFilter } = filter;

  const queryFilter: FilterQuery<ISubCategory> = {
    ...restFilter,

    ...(categoryId && 
        {categoryId: {
        $in: (typeof categoryId === 'string'
          ? categoryId.split(',')
          : [categoryId]
        ).filter((id) =>
            typeof id === 'string' ? Types.ObjectId.isValid(id) : true,
          ).map((id) => (typeof id === 'string' ? getObjectId(id) : id)),
      },
    }),
  };

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

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