import { ApiError } from '@/shared/utils/errors';
import { defaultStatus } from '@/shared/utils/responseCode/httpStatusAlias';
import { ProjectCharge } from '@/modules/projectCharge/projectCharge.model';

import responseCodes from '@/shared/utils/responseCode/responseCode';
import {
  NewCreatedProjectCharge,
  UpdateProjectChargeBody,
} from '@/modules/projectCharge/projectCharge.interface';
import { getObjectId } from '@/shared/utils/commonHelper';
import { safeDeleteById } from '@/shared/utils/guard/ref-guard';

const { ProjectChargeResponseCodes } = responseCodes;

export const createProjectCharge = async (
  data: NewCreatedProjectCharge,
): Promise<boolean> => {
  const projectCharge = await ProjectCharge.create(data);

  if (!projectCharge)
    throw new ApiError(
      defaultStatus.OK,
      'Failed to create projectCharge',
      true,
      '',
      ProjectChargeResponseCodes.PROJECTCHARGE_ERROR,
    );

  return true;
};

export const getProjectChargeById = async (id: string) => {
  const projectCharge = await ProjectCharge.findById(id);
  if (!projectCharge)
    throw new ApiError(
      defaultStatus.OK,
      'ProjectCharge not found',
      true,
      '',
      ProjectChargeResponseCodes.PROJECTCHARGE_NOT_FOUND,
    );

  return projectCharge;
};

export const updateProjectCharge = async (
  id: string,
  updateData: UpdateProjectChargeBody,
): Promise<boolean | null> => {
  try {
    const result = await ProjectCharge.updateOne(
      { _id: getObjectId(id) },
      { $set: updateData },
    );

    if (result.matchedCount === 0)
      throw new ApiError(
        defaultStatus.OK,
        'ProjectCharge not found',
        false,
        '',
        ProjectChargeResponseCodes.PROJECTCHARGE_NOT_FOUND,
      );

    return true;
  } catch (err: unknown) {
    if (err instanceof ApiError) throw err;
    throw new ApiError(
      defaultStatus.OK,
      'Failed to update projectCharge',
      true,
      '',
      ProjectChargeResponseCodes.PROJECTCHARGE_ERROR,
    );
  }
};

export const deleteProjectCharge = async (id: string): Promise<void> => {
  try {
    await safeDeleteById(
      ProjectCharge,
      id,
      ProjectChargeResponseCodes.PROJECTCHARGE_IN_USE,
    );
  } catch (err: unknown) {
    if (err instanceof ApiError) throw err;

    throw new ApiError(
      defaultStatus.OK,
      'Failed to delete project charge',
      true,
      '',
      ProjectChargeResponseCodes.PROJECTCHARGE_ERROR,
    );
  }
};

export const queryProjectCharges = async (
  filter: Record<string, string> = {},
  options = {},
) => {
  const { search, project, ...rest } = filter;

  const query: Record<string, unknown> = {
    ...(project && { project: getObjectId(project) }),
    ...rest,
    ...(search && {
      name: { $regex: search, $options: 'i' },
    }),
  };

  return ProjectCharge.paginate(query, options);
};
