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

import responseCodes from '@/shared/utils/responseCode/responseCode';
import {
  NewCreatedQuotation,
  UpdateQuotationBody,
} from '@/modules/quotation/quotation.interface';
import { getObjectId } from '@/shared/utils/commonHelper';
import { PipelineStage } from 'mongoose';

const { QuotationResponseCodes } = responseCodes;

export const createQuotation = async (
  data: NewCreatedQuotation,
): Promise<boolean> => {
  const { companyId, project, ...rest } = data;

  const filter: Record<string, unknown> = {
    project: getObjectId(project as unknown as string),
  };

  const update = {
    ...rest,
    companyId,
    project,
  };

  const quotation = await Quotation.findOneAndUpdate(
    filter,
    { $set: update },
    { new: true, upsert: true },
  );

  if (!quotation)
    throw new ApiError(
      defaultStatus.OK,
      'Failed to create quotation',
      true,
      '',
      QuotationResponseCodes.QUOTATION_ERROR,
    );

  return true;
};

export const getQuotationById = async (id: string) => {
  const quotation = await Quotation.findById(id);
  if (!quotation)
    throw new ApiError(
      defaultStatus.OK,
      'Quotation not found',
      true,
      '',
      QuotationResponseCodes.QUOTATION_NOT_FOUND,
    );

  return quotation;
};

export const updateQuotation = async (
    id: string,
    updateData: UpdateQuotationBody,
  ): Promise<boolean> => {
    try {
      const updatedQuotation = await Quotation.findByIdAndUpdate(
        getObjectId(id),
        { $set: updateData },
        { new: true },
      );
  
      if (!updatedQuotation) 
        throw new ApiError(
          defaultStatus.OK,
          'Quotation not found',
          false,
          '',
          QuotationResponseCodes.QUOTATION_NOT_FOUND,
        );
      
  
      return true;
    } catch (err: unknown) {
      if (err instanceof ApiError) throw err;
  
      throw new ApiError(
        defaultStatus.OK,
        'Failed to update quotation',
        true,
        '',
        QuotationResponseCodes.QUOTATION_ERROR,
      );
    }
  };
  

export const deleteQuotation = async (id: string): Promise<void> => {
  try {
    const deletedQuotation = await Quotation.findByIdAndDelete(getObjectId(id));

    if (!deletedQuotation)
      throw new ApiError(
        defaultStatus.NOT_FOUND,
        'Quotation not found',
        false,
        '',
        QuotationResponseCodes.QUOTATION_NOT_FOUND,
      );
  } catch (err: unknown) {
    if (err instanceof ApiError) throw err;

    throw new ApiError(
      defaultStatus.INTERNAL_SERVER_ERROR,
      'Failed to delete quotation',
      true,
      '',
      QuotationResponseCodes.QUOTATION_ERROR,
    );
  }
};


export const queryQuotations = async (
  filter: Record<string, string> = {},
  options = {},
) => {
  const { search, ...rawRest } = filter;

  const rest: Record<string, unknown> = { ...rawRest };

  if (rest.companyId)
    rest.companyId = getObjectId(rest.companyId as string);

  if (rest.project)
    rest.project = getObjectId(rest.project as string);
  
  const aggregation: PipelineStage[] = [];

  if (Object.keys(rest).length > 0) 
    aggregation.push({ $match: rest });
  

  aggregation.push(
    {
      $lookup: {
        from: 'projects',
        localField: 'project',
        foreignField: '_id',
        as: 'project',
      },
    },
    {
      $unwind: {
        path: '$project',
        preserveNullAndEmptyArrays: true,
      },
    },
    {
      $project: {
        project: {
          id: '$project._id',
          projectName: '$project.projectName',
        },
        termsConditions: 1,
        createdAt: 1,
        updatedAt: 1,
      },
    },
  );

  if (search) 
    aggregation.push({
      $match: {
        $or: [
          { 'project.projectName': { $regex: search, $options: 'i' } },
        ],
      },
    });
  

  return Quotation.paginate({}, {
    ...options,
    aggregation,
  });
};

