import { createRoute } from "../../../../../modules/api-utils/createRoute";
import { opportunities } from "../../../../../managers/opportunities";
import { apiResponse } from "../../../../../modules/api-utils/apiResponse";
import { ContentfulStatusCode } from "hono/utils/http-status";
import { authMiddleware } from "../../../../middleware/authorization";
import GenericError from "../../../../../Errors/GenericError";
import { z } from "zod";

const cancelProductSchema = z
  .object({
    quantityCancelled: z.number().min(0),
    cancellationReason: z.string().nullable().optional(),
  })
  .strict();

/* PATCH /v1/sales/opportunities/opportunity/:identifier/products/:productId/cancel */
export default createRoute(
  "patch",
  ["/opportunities/opportunity/:identifier/products/:productId/cancel"],
  async (c) => {
    const identifier = c.req.param("identifier");
    const productId = Number(c.req.param("productId"));
    const body = await c.req.json();

    if (!Number.isInteger(productId) || productId <= 0) {
      throw new GenericError({
        status: 400,
        name: "InvalidProductId",
        message: "productId must be a positive integer",
      });
    }

    const input = cancelProductSchema.parse(body);
    const opportunity = await opportunities.fetchRecord(identifier);

    const products = await opportunity.fetchProducts();
    const product = products.find((item) => item.cwForecastId === productId);

    if (!product) {
      throw new GenericError({
        status: 404,
        name: "ForecastItemNotFound",
        message: `Forecast item ${productId} not found on opportunity`,
      });
    }

    const quantity = product.quantity ?? 0;
    if (input.quantityCancelled > quantity) {
      throw new GenericError({
        status: 400,
        name: "InvalidCancelledQuantity",
        message: `quantityCancelled cannot exceed product quantity (${quantity})`,
      });
    }

    await opportunity.setProductCancellation(productId, {
      quantityCancelled: input.quantityCancelled,
      cancellationReason: input.cancellationReason,
    });

    const refreshedProducts = await opportunity.fetchProducts({ fresh: true });
    const updated = refreshedProducts.find(
      (item) => item.cwForecastId === productId,
    );

    if (!updated) {
      throw new GenericError({
        status: 404,
        name: "ForecastItemNotFound",
        message: `Forecast item ${productId} not found on opportunity`,
      });
    }

    const response = apiResponse.successful(
      input.quantityCancelled === 0
        ? "Product uncancelled successfully!"
        : "Product cancellation updated successfully!",
      updated.toJson(),
    );

    return c.json(response, response.status as ContentfulStatusCode);
  },
  authMiddleware({ permissions: ["sales.opportunity.product.update"] }),
);
