import { ApiError } from '@/shared/utils/errors';
import { defaultStatus } from '@/shared/utils/responseCode/httpStatusAlias';
import responseCodes from '@/shared/utils/responseCode/responseCode';
import { NewCreatedFile, UpdateFileBody, IFileFilter } from './files.interface';
import { getObjectId } from '@/shared/utils/commonHelper';
import File from './files.model';

const { FileResponseCodes } = responseCodes;

export const createFile = async (data: NewCreatedFile): Promise<boolean> => {
  const file = await File.create(data);

  if (!file)
    throw new ApiError(
      defaultStatus.NOT_FOUND,
      'Failed to create file',
      true,
      '',
      FileResponseCodes.FILE_ERROR,
    );

  return true;
};

export const getFileById = async (id: string) => {
  const file = await File.findById(id);
  if (!file)
    throw new ApiError(
      defaultStatus.OK,
      'File not found',
      true,
      '',
      FileResponseCodes.FILE_NOT_FOUND,
    );

  return file;
};

export const updateFile = async (
  id: string,
  updateData: UpdateFileBody,
): Promise<boolean | null> => {
  try {
    const result = await File.findByIdAndUpdate(id, updateData, { new: true });

    if (!result)
      throw new ApiError(
        defaultStatus.OK,
        'File not found',
        false,
        '',
        FileResponseCodes.FILE_NOT_FOUND,
      );

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

export const deleteFile = async (id: string): Promise<void> => {
  try {
    const deleted = await File.findByIdAndDelete(getObjectId(id));

    if (!deleted)
      throw new ApiError(
        defaultStatus.NOT_FOUND,
        'File not found',
        false,
        '',
        FileResponseCodes.FILE_NOT_FOUND,
      );
  } catch (err: unknown) {
    if (err instanceof ApiError) throw err;

    throw new ApiError(
      defaultStatus.INTERNAL_SERVER_ERROR,
      'Failed to delete file',
      true,
      '',
      FileResponseCodes.FILE_ERROR,
    );
  }
};

export const queryFiles = async (filter: IFileFilter, options = {}) => {
  const { search, project, category, size, createdBy, status, ...rest } = filter;

  const query: Record<string, unknown> = {
    ...rest,

    ...(search && {
      $or: [
        { name: { $regex: search, $options: 'i' } },
        { category: { $regex: search, $options: 'i' } },
        { size: { $regex: search, $options: 'i' } },
      ],
    }),
    ...(project && {
      project: getObjectId(project),
    }),
    ...(category && {
      category,
    }),
    ...(size && {
      size,
    }),
    ...(createdBy && {
      createdBy: getObjectId(createdBy),
    }),
    ...(status && {
      status,
    }),
  };

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