<script lang="ts">
  import { goto } from "$app/navigation";
  import { clientFetch } from "$lib/client-fetch";
  import type { PermissionMap } from "$lib/permissions";
  import type {
    WorkflowStatusResponse,
    WorkflowAvailableAction,
    WorkflowAction,
    WorkflowActionPayload,
    WorkflowResult,
  } from "$lib/optima-api/modules/sales";
  import {
    STATUS_ID_TO_KEY,
    TERMINAL_STATUSES,
    REOPENABLE_STATUSES,
    QUOTE_CONFIRMED_STATUSES,
  } from "$lib/optima-api/modules/sales";
  import WorkflowActionModal from "../routes/sales/opportunity/[id]/components/WorkflowActionModal.svelte";
  import SendQuoteModal from "../routes/sales/opportunity/[id]/components/SendQuoteModal.svelte";
  import ReviewDecisionModal from "../routes/sales/opportunity/[id]/components/ReviewDecisionModal.svelte";
  import FinalizeModal from "../routes/sales/opportunity/[id]/components/FinalizeModal.svelte";
  import { createEventDispatcher } from "svelte";

  type OpportunityRow = {
    id: string;
    cwOpportunityId?: number;
    name: string;
    closedFlag?: boolean;
    status?: { id?: number; name?: string } | null;
  };

  export let permissions: PermissionMap = {};

  const dispatch = createEventDispatcher<{
    workflowChanged: { opportunityId: string };
  }>();

  // Context menu state
  let isOpen = false;
  let x = 0;
  let y = 0;
  let currentOpp: OpportunityRow | null = null;
  let menuEl: HTMLDivElement;

  // Workflow state
  let workflowStatus: WorkflowStatusResponse | null = null;
  let workflowLoading = false;
  let workflowError: string | null = null;
  let activeModal: WorkflowAction | null = null;
  let isSubmitting = false;
  let preselectedOutcome: "won" | "lost" | null = null;
  let copiedField: string | null = null;

  // Permission checks
  $: canFinalize = permissions["sales.opportunity.finalize"] !== false;
  $: canWin = permissions["sales.opportunity.win"] === true;
  $: canLose = permissions["sales.opportunity.lose"] === true;
  $: canCancel = permissions["sales.opportunity.cancel"] !== false;
  $: canReview = permissions["sales.opportunity.review"] !== false;
  $: canSend = permissions["sales.opportunity.send"] !== false;
  $: canReopen = permissions["sales.opportunity.reopen"] !== false;

  // Derived workflow state
  $: statusKey = workflowStatus
    ? (STATUS_ID_TO_KEY[workflowStatus.currentStatusId] ?? null)
    : null;
  $: isTerminal = statusKey ? TERMINAL_STATUSES.has(statusKey) : false;
  $: isPendingOutcome =
    statusKey === "PendingWon" || statusKey === "PendingLost";
  $: quoteConfirmed = statusKey
    ? QUOTE_CONFIRMED_STATUSES.has(statusKey)
    : false;

  $: availableActions = (
    workflowStatus?.availableActions?.filter((a) => a.permitted) ?? []
  ).filter((a) => actionPermitted(a.action));

  $: resurrectFromPending =
    isPendingOutcome &&
    canFinalize &&
    !availableActions.some((a) => a.action === "resurrect")
      ? ({
          action: "resurrect" as WorkflowAction,
          label: "Open for Revision",
          targetStatuses: [{ key: "Active", id: 58 }],
          requiresNote: true,
          requiresPermission: "sales.opportunity.finalize",
          permitted: true,
          payloadHints: {} as Record<string, string>,
        } satisfies WorkflowAvailableAction)
      : null;

  $: allActions = resurrectFromPending
    ? [...availableActions, resurrectFromPending]
    : availableActions;

  $: finalizeWonAction =
    quoteConfirmed && canWin
      ? allActions.find(
          (a) =>
            a.action === "finalize" &&
            (a.payloadHints as Record<string, string>)?.["outcome"] === '"won"',
        )
      : undefined;
  $: finalizeLostAction =
    quoteConfirmed && canLose
      ? allActions.find(
          (a) =>
            a.action === "finalize" &&
            (a.payloadHints as Record<string, string>)?.["outcome"] ===
              '"lost"',
        )
      : undefined;
  $: nonFinalizeActions = allActions
    .filter((a) => a.action !== "finalize")
    .filter((a, i, arr) => arr.findIndex((b) => b.action === a.action) === i);

  const ACTION_LABELS: Partial<Record<WorkflowAction, string>> = {
    requestReview: "Request Review",
    reviewDecision: "Complete Review",
    sendQuote: "Mark Quote Sent",
    ReadyToSend: "Ready to Send",
    resendQuote: "Mark Quote Resent",
    confirmQuote: "Quote Confirmed",
    beginRevision: "Begin Revising",
    resurrect: "Resurrect",
    cancel: "Cancel",
    reopen: "Reopen",
    acceptNew: "Accept",
  };

  function actionPermitted(action: WorkflowAction): boolean {
    switch (action) {
      case "requestReview":
      case "reviewDecision":
        return canReview;
      case "sendQuote":
      case "ReadyToSend":
      case "resendQuote":
        return canSend;
      case "finalize":
        return canFinalize || canWin || canLose;
      case "cancel":
        return canCancel;
      case "reopen":
        return canReopen;
      case "resurrect":
        return (isPendingOutcome && canFinalize) || canReopen;
      default:
        return true;
    }
  }

  function actionLabel(action: WorkflowAvailableAction): string {
    if (action.action === "resurrect" && isPendingOutcome) {
      return "Open for Revision";
    }
    return ACTION_LABELS[action.action] ?? action.label;
  }

  /** Open the context menu – called from the parent's on:contextmenu handler */
  export function open(e: MouseEvent, opp: OpportunityRow) {
    e.preventDefault();
    currentOpp = opp;
    x = e.clientX;
    y = e.clientY;
    isOpen = true;
    workflowStatus = null;
    workflowError = null;
    copiedField = null;

    // Fetch workflow status in background
    fetchWorkflow(opp.id);

    // Ensure the menu doesn't go offscreen
    requestAnimationFrame(() => {
      if (!menuEl) return;
      const rect = menuEl.getBoundingClientRect();
      if (rect.right > window.innerWidth) {
        x = window.innerWidth - rect.width - 8;
      }
      if (rect.bottom > window.innerHeight) {
        y = window.innerHeight - rect.height - 8;
      }
    });
  }

  function close() {
    isOpen = false;
    currentOpp = null;
    workflowStatus = null;
    workflowLoading = false;
    workflowError = null;
    copiedField = null;
  }

  async function fetchWorkflow(oppId: string) {
    workflowLoading = true;
    try {
      const json = await clientFetch<{ data: WorkflowStatusResponse }>(
        `/sales/opportunity/${oppId}/workflow`,
      );
      workflowStatus = json.data ?? null;
    } catch {
      workflowStatus = null;
    } finally {
      workflowLoading = false;
    }
  }

  function handleOpen() {
    if (!currentOpp) return;
    goto(`/sales/opportunity/${currentOpp.id}`);
    close();
  }

  function handleOpenNewTab() {
    if (!currentOpp) return;
    window.open(`/sales/opportunity/${currentOpp.id}`, "_blank");
    close();
  }

  async function handleCopyLink() {
    if (!currentOpp) return;
    const url = `${window.location.origin}/sales/opportunity/${currentOpp.id}`;
    await navigator.clipboard.writeText(url);
    copiedField = "link";
    setTimeout(() => { if (copiedField === "link") copiedField = null; }, 1200);
  }

  async function handleCopyCwId() {
    if (!currentOpp?.cwOpportunityId) return;
    await navigator.clipboard.writeText(String(currentOpp.cwOpportunityId));
    copiedField = "cwid";
    setTimeout(() => { if (copiedField === "cwid") copiedField = null; }, 1200);
  }

  function openWorkflowAction(action: WorkflowAvailableAction) {
    close();
    activeModal = action.action;
  }

  function openFinalize(outcome: "won" | "lost") {
    close();
    preselectedOutcome = outcome;
    activeModal = "finalize";
  }

  function closeModal() {
    activeModal = null;
    workflowError = null;
    preselectedOutcome = null;
  }

  async function submitAction(
    action: WorkflowAction,
    payload: WorkflowActionPayload,
  ) {
    if (!currentOpp) return null;
    isSubmitting = true;
    workflowError = null;

    try {
      const json = await clientFetch<{
        successful: boolean;
        message?: string;
        data?: { error?: string };
      }>(`/sales/opportunity/${currentOpp.id}/workflow`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ action, payload }),
      });
      if (json.successful === false) {
        workflowError =
          json.message ?? json.data?.error ?? "Workflow action failed";
        return null;
      }
      closeModal();
      dispatch("workflowChanged", { opportunityId: currentOpp.id });
      return json.data as WorkflowResult;
    } catch (err) {
      workflowError =
        err instanceof Error ? err.message : "Workflow action failed";
      return null;
    } finally {
      isSubmitting = false;
    }
  }

  function isSpecialModal(action: WorkflowAction): boolean {
    return ["sendQuote", "resendQuote", "reviewDecision", "finalize"].includes(action);
  }

  function needsConfirmation(action: WorkflowAction): boolean {
    return action === "cancel" || action === "reopen" || action === "resurrect";
  }

  function confirmationMessage(action: WorkflowAction): string {
    if (action === "cancel") return "This cannot be undone unless the opportunity is re-opened. Are you sure?";
    if (action === "reopen") return "Re-opening will set status to Active and log a full audit trail entry. Continue?";
    if (action === "resurrect") return "This will move the opportunity back to Active for further revision. Continue?";
    return "";
  }

  function handleBackdrop(e: MouseEvent) {
    if (e.target === e.currentTarget) close();
  }

  function handleKeydown(e: KeyboardEvent) {
    if (e.key === "Escape") close();
  }
</script>

<svelte:window on:keydown={handleKeydown} on:click={close} />

{#if isOpen && currentOpp}
  <!-- svelte-ignore a11y-click-events-have-key-events -->
  <div
    class="ctx-menu"
    bind:this={menuEl}
    style="left: {x}px; top: {y}px;"
    on:click|stopPropagation
    role="menu"
  >
    <!-- Navigation -->
    <button class="ctx-item" on:click={handleOpen} role="menuitem">
      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
        <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
        <polyline points="15 3 21 3 21 9" />
        <line x1="10" y1="14" x2="21" y2="3" />
      </svg>
      Open Opportunity
    </button>
    <button class="ctx-item" on:click={handleOpenNewTab} role="menuitem">
      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
        <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
        <polyline points="15 3 21 3 21 9" />
        <line x1="10" y1="14" x2="21" y2="3" />
      </svg>
      Open in New Tab
    </button>

    <div class="ctx-divider"></div>

    <!-- Copy actions -->
    <button class="ctx-item" on:click={handleCopyLink} role="menuitem">
      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
        <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
        <path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
      </svg>
      {copiedField === "link" ? "Copied!" : "Copy Link"}
    </button>
    {#if currentOpp.cwOpportunityId}
      <button class="ctx-item" on:click={handleCopyCwId} role="menuitem">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
          <rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
          <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
        </svg>
        {copiedField === "cwid" ? "Copied!" : `Copy CW ID (#${currentOpp.cwOpportunityId})`}
      </button>
    {/if}

    <!-- Workflow actions -->
    {#if workflowLoading}
      <div class="ctx-divider"></div>
      <div class="ctx-loading">
        <span class="ctx-spinner"></span>
        Loading actions…
      </div>
    {:else if workflowStatus && workflowStatus.isOptimaStage && !isTerminal && allActions.length > 0}
      <div class="ctx-divider"></div>
      <div class="ctx-section-label">Workflow</div>
      {#each nonFinalizeActions as action (action.action)}
        <button
          class="ctx-item"
          class:ctx-item-danger={action.action === "cancel"}
          on:click={() => openWorkflowAction(action)}
          role="menuitem"
        >
          {actionLabel(action)}
        </button>
      {/each}
      {#if finalizeWonAction}
        <button class="ctx-item ctx-item-success" on:click={() => openFinalize("won")} role="menuitem">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" width="12" height="12"><polyline points="20 6 9 17 4 12" /></svg>
          Won
        </button>
      {/if}
      {#if finalizeLostAction}
        <button class="ctx-item ctx-item-danger" on:click={() => openFinalize("lost")} role="menuitem">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" width="12" height="12"><line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" /></svg>
          Lost
        </button>
      {/if}
    {/if}
  </div>
{/if}

<!-- ── Modals ── -->
{#if activeModal && currentOpp}
  {#if !isSpecialModal(activeModal)}
    {@const action = allActions.find((a) => a.action === activeModal)}
    {#if action}
      <WorkflowActionModal
        isOpen={true}
        title={actionLabel(action)}
        actionName={action.action}
        requiresNote={action.requiresNote}
        needsConfirmation={needsConfirmation(action.action)}
        confirmationMessage={confirmationMessage(action.action)}
        isDestructive={action.action === "cancel"}
        error={workflowError}
        {isSubmitting}
        on:submit={(e) => submitAction(action.action, e.detail)}
        on:close={closeModal}
      />
    {/if}
  {/if}

  {#if activeModal === "sendQuote" || activeModal === "resendQuote"}
    <SendQuoteModal
      isOpen={true}
      {canFinalize}
      error={workflowError}
      {isSubmitting}
      actionName={activeModal}
      on:submit={(e) => submitAction(activeModal ?? "sendQuote", e.detail)}
      on:close={closeModal}
    />
  {/if}

  {#if activeModal === "reviewDecision"}
    <ReviewDecisionModal
      isOpen={true}
      {canCancel}
      {canSend}
      error={workflowError}
      {isSubmitting}
      on:submit={(e) => submitAction("reviewDecision", e.detail)}
      on:sendQuote={() => { activeModal = "sendQuote"; }}
      on:close={closeModal}
    />
  {/if}

  {#if activeModal === "finalize"}
    <FinalizeModal
      isOpen={true}
      {statusKey}
      hasWon={!!finalizeWonAction}
      hasLost={!!finalizeLostAction}
      {canFinalize}
      initialOutcome={preselectedOutcome}
      error={workflowError}
      {isSubmitting}
      on:submit={(e) => submitAction("finalize", e.detail)}
      on:close={closeModal}
    />
  {/if}
{/if}

<style>
  .ctx-menu {
    position: fixed;
    z-index: 9999;
    min-width: 200px;
    max-width: 280px;
    background: var(--bg-surface, #1e1e2e);
    border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.08));
    border-radius: 10px;
    padding: 5px;
    box-shadow:
      0 8px 30px rgba(0, 0, 0, 0.35),
      0 2px 8px rgba(0, 0, 0, 0.2);
    backdrop-filter: blur(16px);
    animation: ctx-fade-in 0.1s ease-out;
  }

  @keyframes ctx-fade-in {
    from {
      opacity: 0;
      transform: scale(0.96);
    }
    to {
      opacity: 1;
      transform: scale(1);
    }
  }

  .ctx-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 7px 10px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--text-primary, #cdd6f4);
    font-size: 13px;
    font-weight: 450;
    cursor: pointer;
    text-align: left;
    transition: background 0.1s;
    white-space: nowrap;
  }

  .ctx-item:hover {
    background: var(--bg-hover, rgba(255, 255, 255, 0.06));
  }

  .ctx-item:active {
    background: var(--bg-active, rgba(255, 255, 255, 0.1));
  }

  .ctx-item svg {
    flex-shrink: 0;
    opacity: 0.6;
  }

  .ctx-item-danger {
    color: #ef4444;
  }

  .ctx-item-danger:hover {
    background: rgba(239, 68, 68, 0.1);
  }

  .ctx-item-success {
    color: #22c55e;
  }

  .ctx-item-success:hover {
    background: rgba(34, 197, 94, 0.1);
  }

  .ctx-divider {
    height: 1px;
    margin: 4px 6px;
    background: var(--border-subtle, rgba(255, 255, 255, 0.06));
  }

  .ctx-section-label {
    padding: 4px 10px 2px;
    font-size: 11px;
    font-weight: 600;
    color: var(--text-tertiary, rgba(205, 214, 244, 0.4));
    text-transform: uppercase;
    letter-spacing: 0.04em;
    user-select: none;
  }

  .ctx-loading {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 10px;
    font-size: 12px;
    color: var(--text-secondary, rgba(205, 214, 244, 0.6));
  }

  .ctx-spinner {
    width: 12px;
    height: 12px;
    border: 2px solid var(--border-subtle, rgba(255, 255, 255, 0.1));
    border-top-color: var(--text-secondary, rgba(205, 214, 244, 0.6));
    border-radius: 50%;
    animation: ctx-spin 0.6s linear infinite;
  }

  @keyframes ctx-spin {
    to {
      transform: rotate(360deg);
    }
  }
</style>
