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 updateSchema = z
  .object({
    name: z.string().min(1).optional(),
    notes: z.string().optional(),
    interest: z.enum(["HOT", "WARM", "COLD"]).nullable().optional(),
    rating: z.object({ id: z.number() }).optional(),
    type: z.object({ id: z.number() }).optional(),
    stage: z.object({ id: z.number() }).optional(),
    status: z.object({ id: z.number() }).optional(),
    priority: z.object({ id: z.number() }).optional(),
    campaign: z.object({ id: z.number() }).optional(),
    primarySalesRep: z.object({ id: z.number() }).optional(),
    secondarySalesRep: z.object({ id: z.number() }).nullable().optional(),
    company: z.object({ id: z.number() }).optional(),
    contact: z.object({ id: z.number() }).nullable().optional(),
    site: z.object({ id: z.number() }).nullable().optional(),
    expectedCloseDate: z
      .string()
      .optional()
      .transform((v) => (v ? new Date(v).toISOString() : v)),
    customerPO: z.string().nullable().optional(),
    source: z.string().nullable().optional(),
    locationId: z.number().optional(),
    businessUnitId: z.number().optional(),
  })
  .refine((d) => Object.values(d).some((v) => v !== undefined), {
    message: "At least one field must be provided",
  });

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

    const item = await opportunities.fetchRecord(identifier);

    try {
      const updated = await item.updateOpportunity(data);

      const response = apiResponse.successful(
        "Opportunity updated successfully!",
        updated.toJson()
      );

      return c.json(response, response.status as ContentfulStatusCode);
    } catch (err) {
      const isAxios =
        err != null && typeof err === "object" && "isAxiosError" in err;

      if (isAxios) {
        const axiosErr = err as any;
        const cwStatus: number = axiosErr.response?.status ?? 502;
        const cwData = axiosErr.response?.data;
        const cwMessage: string =
          cwData?.message ?? "Failed to update the opportunity in ConnectWise";
        const cwErrors: unknown[] | undefined = Array.isArray(cwData?.errors)
          ? cwData.errors
          : undefined;

        return c.json(
          {
            status: cwStatus,
            message: cwMessage,
            error: "ConnectWiseUpdateError",
            successful: false,
            errors: cwErrors,
            meta: { timestamp: Date.now() },
          },
          cwStatus as ContentfulStatusCode
        );
      }

      throw new GenericError({
        status: 500,
        name: "OpportunitySaveError",
        message: "Failed to save opportunity data",
        cause: err instanceof Error ? err.message : String(err),
      });
    }
  },
  authMiddleware({ permissions: ["sales.opportunity.update"] })
);
