import { Request, Response } from 'express';

import * as paymentService from '@/modules/customer/payment/payment.service';
import * as rulesService from '@/modules/rules/rules.service';
import catchAsync from '@/shared/utils/catchAsync';
import responseCodes from '@/shared/utils/responseCode/responseCode';
import { UserType } from '@/shared/constants/enum.constant';
import { ApiError } from '@/shared/utils/errors';
import { defaultStatus } from '@/shared/utils/responseCode/httpStatusAlias';

const { CustomerResponseCodes } = responseCodes;

const enforceEditCustomerFinancialRule = async (req: Request) => {
  const { userType, company } = req.user;
  const companyId = company?.id ? company.id.toString() : '';

  if (userType === UserType.ADMIN || userType === UserType.SUPERADMIN) return;
  if (!companyId) return;

  const rules = (await rulesService.getRules(
    companyId,
    'edit_customer_details',
  )) as Record<string, boolean>;

  if (!rules.edit_customer_details)
    throw new ApiError(
      defaultStatus.FORBIDDEN,
      'Editing customer financial details is disabled by company rules',
      true,
      '',
      CustomerResponseCodes.COMPANY_ERROR,
    );
};

export const createPayment = catchAsync(async (req: Request, res: Response) => {
  await enforceEditCustomerFinancialRule(req);
  req.body = {
    ...req.body,
    userId: req.user.id,
    customerId: req.params.id,
  };
  const payment = await paymentService.upsertPaymentTimeline(req.body);
  res.success(
    payment,
    CustomerResponseCodes.SUCCESS,
    'Payment Created Successfully',
  );
});

export const getPaymentTimelines = catchAsync(
  async (req: Request, res: Response) => {
    const payload = {
      company: req.user.company?.id,
      customerId: req.params.id as string,
    };
    const payment = await paymentService.getPaymentTimelines(payload);
    res.success(
      payment,
      CustomerResponseCodes.SUCCESS,
      'Payment Fetched Successfully',
    );
  },
);

export const sendPaymentReminder = catchAsync(async (req: Request, res: Response) => {
  await enforceEditCustomerFinancialRule(req);
  const payload = {
    companyId: req.user.company?.id ? req.user.company.id.toString() : '',
    customerId: req.params.id as string,
    stageId: req.body.stageId as string,
  };
  const result = await paymentService.sendPaymentDueReminder(payload);
  res.success(
    result,
    CustomerResponseCodes.SUCCESS,
    'Payment reminder sent successfully',
  );
});

export const addPaymentEntry = catchAsync(async (req: Request, res: Response) => {
  await enforceEditCustomerFinancialRule(req);
  const payload = {
    companyId: req.user.company?.id ? req.user.company.id.toString() : '',
    customerId: req.params.id as string,
    stageId: req.params.stageId as string,
    amount: Number(req.body.amount),
    receivedAt: req.body.receivedAt ? new Date(req.body.receivedAt) : undefined,
    bankAccountId: req.body.bankAccountId as string | undefined,
    method: req.body.method,
    note: req.body.note,
    userId: req.user.id,
  };
  const result = await paymentService.addPaymentEntryToStage(payload);
  res.success(
    result,
    CustomerResponseCodes.SUCCESS,
    'Payment entry added successfully',
  );
});

export const updatePaymentEntry = catchAsync(async (req: Request, res: Response) => {
  await enforceEditCustomerFinancialRule(req);
  const body = req.body || {};
  if (Object.keys(body).length === 0) {
    throw new ApiError(
      defaultStatus.BAD_REQUEST,
      'No fields to update',
      true,
      '',
      CustomerResponseCodes.COMPANY_ERROR,
    );
  }

  const updates: {
    amount?: number;
    receivedAt?: Date;
    bankAccountId?: string | null;
    method?: string;
    note?: string;
  } = {};

  if (body.amount !== undefined) updates.amount = Number(body.amount);
  if (body.receivedAt !== undefined) updates.receivedAt = new Date(body.receivedAt);
  if (body.bankAccountId !== undefined) {
    updates.bankAccountId =
      body.bankAccountId === '' || body.bankAccountId === null
        ? null
        : (body.bankAccountId as string);
  }
  if (body.method !== undefined) updates.method = body.method as string;
  if (body.note !== undefined) updates.note = body.note as string;

  const result = await paymentService.updatePaymentEntry({
    companyId: req.user.company?.id ? req.user.company.id.toString() : '',
    customerId: req.params.id as string,
    stageId: req.params.stageId as string,
    entryId: req.params.entryId as string,
    updates,
    userId: req.user.id,
  });
  res.success(
    result,
    CustomerResponseCodes.SUCCESS,
    'Payment entry updated successfully',
  );
});

export const deletePaymentEntry = catchAsync(async (req: Request, res: Response) => {
  await enforceEditCustomerFinancialRule(req);
  const result = await paymentService.deletePaymentEntry({
    companyId: req.user.company?.id ? req.user.company.id.toString() : '',
    customerId: req.params.id as string,
    stageId: req.params.stageId as string,
    entryId: req.params.entryId as string,
    userId: req.user.id,
  });
  res.success(
    result,
    CustomerResponseCodes.SUCCESS,
    'Payment entry deleted successfully',
  );
});
