import { Types } from 'mongoose';
import { ApiError } from '@/shared/utils/errors';
import { defaultStatus } from '@/shared/utils/responseCode/httpStatusAlias';
import { PaymentPlan } from '@/modules/paymentPlan/paymentPlan.model';

import responseCodes from '@/shared/utils/responseCode/responseCode';
import {
  NewCreatedPaymentPlan,
  UpdatePaymentPlanBody,
} from '@/modules/paymentPlan/paymentPlan.interface';
import { getObjectId } from '@/shared/utils/commonHelper';
import { safeDeleteById } from '@/shared/utils/guard/ref-guard';

const { PaymentPlanResponseCodes } = responseCodes;

export const createPaymentPlan = async (
  data: NewCreatedPaymentPlan,
): Promise<boolean> => {
  const paymentPlan = await PaymentPlan.create(data);

  if (!paymentPlan)
    throw new ApiError(
      defaultStatus.OK,
      'Failed to create paymentPlan',
      true,
      '',
      PaymentPlanResponseCodes.PAYMENTPLAN_ERROR,
    );

  return true;
};

export const getPaymentPlanById = async (id: string) => {
  const paymentPlan = await PaymentPlan.findById(id);
  if (!paymentPlan)
    throw new ApiError(
      defaultStatus.OK,
      'PaymentPlan not found',
      true,
      '',
      PaymentPlanResponseCodes.PAYMENTPLAN_NOT_FOUND,
    );

  return paymentPlan;
};

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

    if (result.matchedCount === 0)
      throw new ApiError(
        defaultStatus.OK,
        'PaymentPlan not found',
        false,
        '',
        PaymentPlanResponseCodes.PAYMENTPLAN_NOT_FOUND,
      );

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

export const deletePaymentPlan = async (id: string): Promise<boolean> => {
  try {
    await safeDeleteById(
      PaymentPlan,
      id,
      PaymentPlanResponseCodes.PAYMENTPLAN_IN_USE,
    );

    return true;
  } catch (err: unknown) {
    if (err instanceof ApiError) throw err;

    throw new ApiError(
      defaultStatus.INTERNAL_SERVER_ERROR,
      'Failed to delete bank account',
      true,
      '',
      PaymentPlanResponseCodes.PAYMENTPLAN_ERROR,
    );
  }
};

export const queryPaymentPlans = async (
  filter: Record<string, string> = {},
  options = {},
  companyId?: string | Types.ObjectId,
) => {
  const { search, project, status, ...rest } = filter;

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

  if (project) {
    let projectObjectId;
    try {
      projectObjectId = getObjectId(project);
    } catch {
      projectObjectId = undefined;
    }

    query.$or = projectObjectId
      ? [{ project: projectObjectId }, { project }]
      : [{ project }];

    if (process.env.NODE_ENV === 'development') {
      console.debug('[paymentPlan] queryPaymentPlans project filter query:', query);
    }
  }

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