import { z } from "zod";
import { createRoute } from "../../../../../modules/api-utils/createRoute";
import { apiResponse } from "../../../../../modules/api-utils/apiResponse";
import { ContentfulStatusCode } from "hono/utils/http-status";
import { authMiddleware } from "../../../../middleware/authorization";
import { opportunities } from "../../../../../managers/opportunities";
import { cwMembers } from "../../../../../managers/cwMembers";
import GenericError from "../../../../../Errors/GenericError";
import {
  processOpportunityAction,
  type WorkflowAction,
  type WorkflowUser,
} from "../../../../../workflows/wf.opportunity";

// ── Zod schemas ───────────────────────────────────────────────────────────

const basePayload = z.object({
  note: z.string().optional(),
  timeStarted: z.string().datetime().optional(),
  timeEnded: z.string().datetime().optional(),
});

const noteRequiredPayload = z.object({
  note: z.string().min(1, "A non-empty note is required."),
  timeStarted: z.string().datetime().optional(),
  timeEnded: z.string().datetime().optional(),
});

const dispatchSchema = z.discriminatedUnion("action", [
  z.object({
    action: z.literal("acceptNew"),
    payload: basePayload,
  }),
  z.object({
    action: z.literal("requestReview"),
    payload: noteRequiredPayload,
  }),
  z.object({
    action: z.literal("reviewDecision"),
    payload: noteRequiredPayload.extend({
      decision: z.enum(["approve", "reject", "send", "cancel"]),
    }),
  }),
  z.object({
    action: z.literal("sendQuote"),
    payload: basePayload.extend({
      quoteConfirmed: z.boolean().optional(),
      won: z.boolean().optional(),
      lost: z.boolean().optional(),
      finalize: z.boolean().optional(),
      needsRevision: z.boolean().optional(),
    }),
  }),
  z.object({
    action: z.literal("markReadyToSend"),
    payload: basePayload,
  }),
  z.object({
    action: z.literal("confirmQuote"),
    payload: basePayload,
  }),
  z.object({
    action: z.literal("finalize"),
    payload: noteRequiredPayload.extend({
      outcome: z.enum(["won", "lost"]),
    }),
  }),
  z.object({
    action: z.literal("resurrect"),
    payload: noteRequiredPayload,
  }),
  z.object({
    action: z.literal("beginRevision"),
    payload: basePayload,
  }),
  z.object({
    action: z.literal("resendQuote"),
    payload: basePayload.extend({
      quoteConfirmed: z.boolean().optional(),
      won: z.boolean().optional(),
      lost: z.boolean().optional(),
      finalize: z.boolean().optional(),
      needsRevision: z.boolean().optional(),
    }),
  }),
  z.object({
    action: z.literal("cancel"),
    payload: noteRequiredPayload,
  }),
  z.object({
    action: z.literal("reopen"),
    payload: noteRequiredPayload,
  }),
  z.object({
    action: z.literal("sendBackForRevision"),
    payload: noteRequiredPayload,
  }),
  z.object({
    action: z.literal("createScheduleEntry"),
    payload: basePayload.extend({
      activityTypeValue: z.enum(["Follow-Up", "Appointment", "Admin"]),
      dueDate: z.string().optional(),
      startTime: z.string().optional(),
      endTime: z.string().optional(),
    }),
  }),
]);

// ── Route ─────────────────────────────────────────────────────────────────

/* POST /v1/sales/opportunities/opportunity/:identifier/workflow */
export default createRoute(
  "post",
  ["/opportunities/opportunity/:identifier/workflow"],
  async (c) => {
    try {
      const identifier = c.req.param("identifier");
      const body = await c.req.json();
      const parsed = dispatchSchema.parse(body);
      const user = c.get("user");

      // ── Resolve opportunity ────────────────────────────────────────────
      const opportunity = await opportunities.fetchItem(identifier);

      // ── Build WorkflowUser ─────────────────────────────────────────────
      if (!user.cwIdentifier) {
        throw new GenericError({
          status: 400,
          name: "MissingCwIdentifier",
          message:
            "Your account is not linked to a ConnectWise member. A CW member association is required to execute workflow actions.",
        });
      }

      const cwMember = await cwMembers.fetch(user.cwIdentifier);
      const permissions = await user.readAllPermissions();

      const workflowUser: WorkflowUser = {
        id: user.id,
        cwMemberId: cwMember.cwMemberId,
        permissions,
      };

      // ── Dispatch ───────────────────────────────────────────────────────
      const result = await processOpportunityAction(
        opportunity,
        parsed as WorkflowAction,
        workflowUser,
      );

      if (!result.success) {
        console.error(
          `[Workflow Dispatch] Transition failed for opportunity "${identifier}":`,
          result.error,
        );
        const response = apiResponse.error(
          new GenericError({
            status: 422,
            name: "WorkflowTransitionFailed",
            message: result.error ?? "Workflow action failed.",
          }),
        );
        return c.json(
          {
            ...response,
            data: {
              previousStatusId: result.previousStatusId,
              previousStatus: result.previousStatus,
              newStatusId: result.newStatusId,
              newStatus: result.newStatus,
            },
          },
          response.status as ContentfulStatusCode,
        );
      }

      const response = apiResponse.successful(
        "Workflow action completed successfully.",
        {
          previousStatusId: result.previousStatusId,
          previousStatus: result.previousStatus,
          newStatusId: result.newStatusId,
          newStatus: result.newStatus,
          activitiesCreated: result.activitiesCreated.map((a) => a.toJson()),
          coldCheck: result.coldCheck,
        },
      );
      return c.json(response, response.status as ContentfulStatusCode);
    } catch (err: any) {
      console.error("[Workflow Dispatch] Unhandled error:", err);
      if (err?.response?.data) {
        console.error(
          "[Workflow Dispatch] CW response body:",
          JSON.stringify(err.response.data, null, 2),
        );
      }
      throw err;
    }
  },
  authMiddleware({ permissions: ["sales.opportunity.workflow"] }),
);
