// t-paliad-252 / m/paliad#83 — withdraw warning modal.
//
// Before t-paliad-252 the deadline + appointment detail pages did a
// confirm() dialog before POSTing to /api/approval-requests/{id}/revoke.
// For pending CREATE lifecycles that endpoint silently DELETES the
// underlying entity row — m's "withdrawing the approval deletes the event"
// surprise.
//
// This modal replaces the confirm() with three explicit paths:
//
//   1. Cancel                       — does nothing
//   2. Termin bearbeiten (primary)  — opens the edit form; saving routes
//                                     through POST /approval-requests/{id}/
//                                     edit-entity which keeps the request
//                                     pending and merges the new fields
//                                     into approval_request.payload
//   3. Endgültig zurückziehen +     — destructive; current /revoke
//      löschen                        behaviour (delete for CREATE, revert
//                                     for UPDATE/COMPLETE, cancel for
//                                     DELETE-lifecycle requests)
//
// Built on the unified openModal() primitive (t-paliad-217 Slice A) so the
// three-button row sits cleanly inside the body — the primitive only
// supports one secondary action, but we paint the destructive button as a
// separate row above the footer.

import { t } from "../i18n";
import { openModal } from "./modal";

export type WithdrawAction = "edit" | "withdraw";

export interface WithdrawWarningArgs {
  // entityType drives the copy ("event" vs "appointment" labels).
  entityType: "deadline" | "appointment";
  // lifecycleEvent of the pending request; copy adapts (CREATE warns about
  // deletion; UPDATE/COMPLETE warn about revert; DELETE warns about
  // cancelling the deletion request).
  lifecycleEvent: "create" | "update" | "complete" | "delete" | string;
}

// openWithdrawWarningModal resolves with the chosen action, or null if the
// user dismissed via Cancel / Esc / backdrop / browser back-button.
export async function openWithdrawWarningModal(
  args: WithdrawWarningArgs,
): Promise<WithdrawAction | null> {
  const body = document.createElement("div");
  body.className = "withdraw-warning-body";

  // Lead paragraph + sub-paragraph adapt to lifecycle so the user always
  // knows what the destructive button will actually do. The /revoke
  // backend behaviour:
  //   - create   → DELETE the entity (the "surprise" m flagged)
  //   - update   → revert to pre_image
  //   - complete → revert to pre-complete state
  //   - delete   → cancel the delete request (entity stays alive)
  const intro = document.createElement("p");
  intro.className = "withdraw-warning-intro";
  intro.textContent = leadCopyFor(args);
  body.appendChild(intro);

  const sub = document.createElement("p");
  sub.className = "withdraw-warning-sub muted";
  sub.textContent = subCopyFor(args);
  body.appendChild(sub);

  // The destructive button lives inside the body — the openModal primitive
  // only exposes one secondary button slot, and we want the safe "Edit"
  // path to be the primary CTA. Painting it in red here, separated from
  // the footer, signals "this is the dangerous option" without competing
  // visually with the primary CTA.
  const destructiveRow = document.createElement("div");
  destructiveRow.className = "withdraw-warning-destructive-row";
  const destructiveBtn = document.createElement("button");
  destructiveBtn.type = "button";
  destructiveBtn.className = "btn btn-danger withdraw-warning-destructive-btn";
  destructiveBtn.textContent = t("approvals.withdraw.destructive.label");
  destructiveRow.appendChild(destructiveBtn);
  body.appendChild(destructiveRow);

  return new Promise<WithdrawAction | null>((resolve) => {
    let chosen: WithdrawAction | null = null;

    // The destructive button has to close the modal and return "withdraw".
    // We need access to the modal's internal close() — fortunately openModal
    // exposes it via the primary handler's first arg. We pass through the
    // outer resolve and let the primary handler (Edit) own the close-fn
    // route. For the destructive button we resolve the outer promise
    // directly and then synthesise an ESC keypress so the modal dismisses
    // — or, simpler, set chosen and use the secondary "Cancel" path that
    // the modal already supports. (openModal's onClose fires on every
    // dismiss path including the primary handler resolution.)
    destructiveBtn.addEventListener("click", () => {
      chosen = "withdraw";
      // The unified openModal primitive (modal.ts) wires its dismiss path
      // through the native <dialog>'s `cancel` event. Dispatching it on
      // the parent <dialog> runs the same finish() → onClose → resolve
      // sequence as ESC / backdrop. We then map the resolved `null` back
      // to "withdraw" via the captured `chosen` in onClose below.
      const dialogEl = body.closest("dialog");
      dialogEl?.dispatchEvent(new Event("cancel"));
    });

    void openModal<WithdrawAction>({
      title: t("approvals.withdraw.modal.title"),
      body,
      size: "md",
      classNames: "withdraw-warning-modal",
      primary: {
        label: t("approvals.withdraw.primary.label"),
        handler: (close) => {
          chosen = "edit";
          close("edit");
        },
      },
      secondary: { label: t("approvals.withdraw.cancel") },
      onClose: () => {
        // Resolves whatever was chosen via the destructive button OR the
        // primary handler. ESC / backdrop / secondary clear `chosen` to
        // null which is the right "cancel" semantics.
        resolve(chosen);
      },
    });
  });
}

function leadCopyFor(args: WithdrawWarningArgs): string {
  switch (args.lifecycleEvent) {
    case "create":
      return args.entityType === "appointment"
        ? t("approvals.withdraw.lead.create.appointment")
        : t("approvals.withdraw.lead.create.deadline");
    case "delete":
      return t("approvals.withdraw.lead.delete");
    default:
      // update / complete / unknown → revert semantics
      return t("approvals.withdraw.lead.update");
  }
}

function subCopyFor(args: WithdrawWarningArgs): string {
  switch (args.lifecycleEvent) {
    case "create":
      return t("approvals.withdraw.sub.create");
    case "delete":
      return t("approvals.withdraw.sub.delete");
    default:
      return t("approvals.withdraw.sub.update");
  }
}
