<script lang="ts">
  import { createEventDispatcher, onMount } from "svelte";
  import { clientFetch } from "$lib/client-fetch";
  import type {
    SalesOpportunity,
    OpportunityActivity,
    WorkflowHistoryEntry,
  } from "$lib/optima-api/modules/sales";
  import type { PermissionMap } from "$lib/permissions";
  import type {
    OpportunityNote,
    OpportunityContact,
    OpportunityProduct,
  } from "../types";
  import {
    formatDate,
    formatDateTime,
    formatCurrency,
    statusColorClass,
  } from "../types";

  const dispatch = createEventDispatcher<{
    selectProduct: number;
    switchTab: string;
    viewQuote: string;
  }>();

  export let opportunity: SalesOpportunity | null;
  export let opportunityId: string;
  export let notes: OpportunityNote[];
  export let contacts: OpportunityContact[];
  export let products: OpportunityProduct[];
  export let permissions: PermissionMap = {};

  let workflowHistory: WorkflowHistoryEntry[] = [];

  onMount(() => {
    clientFetch<{ data: { activities: WorkflowHistoryEntry[] } }>(
      `/sales/opportunity/${opportunityId}/workflow/history`,
    )
      .then((json) => {
        workflowHistory = json.data?.activities ?? [];
      })
      .catch(() => {
        // silently ignore — timeline falls back to raw activities
      });
  });

  $: canViewCost = permissions["sales.opportunity.view_cost"] !== false;
  $: canViewMargin = permissions["sales.opportunity.view_margin"] !== false;

  // ── Active (non-cancelled) products ──
  $: activeProducts = products.filter((p) => p.cancellationType !== "full");

  // ── Cancellation stats ──
  $: fullyCancelled = products.filter((p) => p.cancellationType === "full");
  $: partiallyCancelled = products.filter(
    (p) => p.cancellationType === "partial",
  );
  $: hasCancellations =
    fullyCancelled.length > 0 || partiallyCancelled.length > 0;

  // ── Financial KPIs from products ──
  $: totalRevenue = activeProducts.reduce((s, p) => s + (p.revenue ?? 0), 0);
  $: totalCost = activeProducts.reduce((s, p) => s + (p.cost ?? 0), 0);
  $: totalMargin = totalRevenue - totalCost;
  $: marginPct = totalCost > 0 ? (totalMargin / totalCost) * 100 : 0;
  $: taxRate = (opportunity?.expectedSalesTaxRate ?? 0) / 100;
  $: taxableRevenue = activeProducts
    .filter((p) => p.taxableFlag)
    .reduce((s, p) => s + (p.revenue ?? 0), 0);
  $: totalTax =
    opportunity?.totalSalesTax != null
      ? opportunity.totalSalesTax
      : taxRate > 0
        ? taxableRevenue * taxRate
        : 0;
  $: grandTotal = totalRevenue + totalTax;

  // ── Product class breakdown ──
  $: classBreakdown = (() => {
    const map = new Map<
      string,
      { revenue: number; cost: number; count: number }
    >();
    for (const p of activeProducts) {
      const cls = p.productClass || "Other";
      const entry = map.get(cls) ?? { revenue: 0, cost: 0, count: 0 };
      entry.revenue += p.revenue ?? 0;
      entry.cost += p.cost ?? 0;
      entry.count++;
      map.set(cls, entry);
    }
    return [...map.entries()]
      .sort((a, b) => b[1].revenue - a[1].revenue)
      .map(([name, data]) => ({
        name,
        ...data,
        margin: data.revenue - data.cost,
        marginPct:
          data.cost > 0 ? ((data.revenue - data.cost) / data.cost) * 100 : 0,
      }));
  })();

  // ── Top products by revenue (up to 15), active first then cancelled ──
  $: topProducts = (() => {
    const active = [...activeProducts]
      .sort((a, b) => (b.revenue ?? 0) - (a.revenue ?? 0))
      .slice(0, 15);
    const cancelled = [...fullyCancelled]
      .sort((a, b) => (b.revenue ?? 0) - (a.revenue ?? 0))
      .slice(0, Math.max(0, 15 - active.length));
    return [...active, ...cancelled];
  })();

  /** Effective quantity after cancellations */
  function effectiveQty(p: OpportunityProduct): number {
    return (p.quantity ?? 0) - (p.quantityCancelled ?? 0);
  }

  // ── Timeline entries — milestones + workflow activities, sorted chronologically ──
  type TimelineEntry = {
    label: string;
    date: string;
    kind: "milestone" | "activity";
    dotClass?: string;
    textClass?: string;
    highlight?: boolean;
    // Activity-specific rich data
    activity?: OpportunityActivity;
    quoteId?: string | null;
    closed?: boolean | null;
    closedAt?: string | null;
  };

  // Collapse threshold: show first N and last N when total > MAX
  const TIMELINE_MAX = 8;
  const TIMELINE_EDGE = 4;

  $: timelineCollapsed = timeline.length > TIMELINE_MAX;
  $: visibleTimeline = timelineCollapsed
    ? [...timeline.slice(0, TIMELINE_EDGE), ...timeline.slice(-TIMELINE_EDGE)]
    : timeline;
  $: hiddenCount = timelineCollapsed ? timeline.length - TIMELINE_EDGE * 2 : 0;

  function getOptimaType(activity: OpportunityActivity): string | null {
    const cf = activity.customFields?.find(
      (f) => f.id === 45 || f.caption === "Optima_Type",
    );
    return cf?.value ?? null;
  }

  function activityDotClass(type: string | null): string {
    const map: Record<string, string> = {
      "Opportunity Created": "ov-dot-created",
      "Opportunity Setup": "ov-dot-setup",
      "Opportunity Review": "ov-dot-review",
      "Quote Sent": "ov-dot-sent",
      "Quote Confirmed": "ov-dot-confirmed",
      "Quote Sent & Confirmed": "ov-dot-sent-confirmed",
      Revision: "ov-dot-revision",
      Finalized: "ov-dot-finalized",
      Converted: "ov-dot-converted",
      "Quote Generated": "ov-dot-generated",
    };
    return map[type ?? ""] ?? "ov-dot-default";
  }

  function activityTextClass(type: string | null): string {
    const map: Record<string, string> = {
      "Opportunity Created": "ov-text-created",
      "Opportunity Setup": "ov-text-setup",
      "Opportunity Review": "ov-text-review",
      "Quote Sent": "ov-text-sent",
      "Quote Confirmed": "ov-text-confirmed",
      "Quote Sent & Confirmed": "ov-text-sent-confirmed",
      Revision: "ov-text-revision",
      Finalized: "ov-text-finalized",
      Converted: "ov-text-converted",
      "Quote Generated": "ov-text-generated",
    };
    return map[type ?? ""] ?? "";
  }

  function parseStatusTransition(
    notes: string | undefined,
  ): { from: string; to: string } | null {
    if (!notes) return null;
    const match = notes.match(/\[(\w+)\s*→\s*(\w+)\]/);
    if (match) return { from: match[1], to: match[2] };
    return null;
  }

  function isSystemActivity(activity: OpportunityActivity): boolean {
    return !activity.assignTo?.name && !activity.cwEnteredBy;
  }

  function assignedDisplay(activity: OpportunityActivity): string {
    if (isSystemActivity(activity)) return "System";
    return activity.assignTo?.name ?? activity.cwEnteredBy ?? "Unknown";
  }

  function isOpenActivity(activity: OpportunityActivity): boolean {
    if (activity.closed != null) return !activity.closed;
    if (activity.status?.id != null) return activity.status.id !== 2;
    return !activity.dateEnd;
  }

  function activityBadgeClass(type: string | null): string {
    const map: Record<string, string> = {
      "Opportunity Created": "at-type-created",
      "Opportunity Setup": "at-type-setup",
      "Opportunity Review": "at-type-review",
      "Quote Sent": "at-type-sent",
      "Quote Confirmed": "at-type-confirmed",
      "Quote Sent & Confirmed": "at-type-sent-confirmed",
      Revision: "at-type-revision",
      Finalized: "at-type-finalized",
      Converted: "at-type-converted",
      "Quote Generated": "at-type-generated",
    };
    return map[type ?? ""] ?? "at-type-default";
  }

  function activityIcon(type: string | null): string {
    switch (type) {
      case "Opportunity Created":
        return "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z";
      case "Opportunity Setup":
        return "M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z";
      case "Opportunity Review":
        return "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8zM12 9a3 3 0 100 6 3 3 0 000-6z";
      case "Quote Sent":
        return "M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z";
      case "Quote Confirmed":
        return "M22 11.08V12a10 10 0 11-5.93-9.14M22 4L12 14.01l-3-3";
      case "Quote Sent & Confirmed":
        return "M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z";
      case "Revision":
        return "M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z";
      case "Finalized":
        return "M9 11l3 3L22 4M21 12v7a2 2 0 01-2 2H5a2 2 0 01-2-2V5a2 2 0 012-2h11";
      case "Converted":
        return "M17 1l4 4-4 4M3 11V9a4 4 0 014-4h14M7 23l-4-4 4-4M21 13v2a4 4 0 01-4 4H3";
      case "Quote Generated":
        return "M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8zM14 2v6h6M16 13H8M16 17H8M10 9H8";
      default:
        return "M12 2v20M17 7l-5 5-5-5M2 12h20M7 17l5-5 5 5";
    }
  }

  $: timeline = (() => {
    const entries: TimelineEntry[] = [];

    // Key milestone dates
    if (opportunity?.createdAt)
      entries.push({
        label: "Created",
        date: opportunity.createdAt,
        kind: "milestone",
      });
    if (opportunity?.expectedCloseDate)
      entries.push({
        label: "Expected Close",
        date: opportunity.expectedCloseDate,
        kind: "milestone",
        highlight: true,
      });

    // Workflow activities — prefer enriched history, fall back to raw activities
    if (workflowHistory.length > 0) {
      for (const h of workflowHistory) {
        const date =
          h.activity.cwDateEntered ?? h.activity.dateStart ?? "";
        if (!date) continue;
        entries.push({
          label: h.optimaType,
          date,
          kind: "activity",
          dotClass: activityDotClass(h.optimaType),
          textClass: activityTextClass(h.optimaType),
          activity: h.activity,
          quoteId: h.quoteId ?? null,
          closed: h.closed ?? null,
          closedAt: h.closedAt ?? null,
        });
      }
    } else {
      for (const a of opportunity?.activities ?? []) {
        const optimaType = getOptimaType(a);
        if (!optimaType) continue;
        const date = a.cwDateEntered ?? a.dateStart ?? "";
        if (!date) continue;
        entries.push({
          label: optimaType,
          date,
          kind: "activity",
          dotClass: activityDotClass(optimaType),
          textClass: activityTextClass(optimaType),
          activity: a,
          quoteId: null,
          closed: null,
          closedAt: null,
        });
      }
    }

    // Sort chronologically (oldest first)
    return entries.sort((a, b) => a.date.localeCompare(b.date));
  })();

  $: isClosedOpportunity = (() => {
    if (!opportunity) return false;
    const statusText =
      `${opportunity.status?.name ?? ""} ${opportunity.type?.name ?? ""}`.toLowerCase();
    return (
      !!opportunity.closedFlag ||
      !!opportunity.closedDate ||
      statusText.includes("won") ||
      statusText.includes("lost")
    );
  })();

  // Days until expected close
  $: daysUntilClose = (() => {
    if (!opportunity?.expectedCloseDate || isClosedOpportunity) return null;
    const raw = opportunity.expectedCloseDate;
    const dateOnly = raw.split("T")[0];
    const close = new Date(dateOnly + "T00:00:00");
    const now = new Date();
    const closeDay = new Date(
      close.getFullYear(),
      close.getMonth(),
      close.getDate(),
    );
    const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
    const diff = Math.round(
      (closeDay.getTime() - today.getTime()) / (1000 * 60 * 60 * 24),
    );
    return diff;
  })();

  // Age in days
  $: ageDays = (() => {
    if (!opportunity?.createdAt) return null;
    return Math.floor(
      (Date.now() - new Date(opportunity.createdAt).getTime()) /
        (1000 * 60 * 60 * 24),
    );
  })();

  function marginHealthColor(pct: number): string {
    if (pct >= 30) return "healthy";
    if (pct >= 15) return "moderate";
    if (pct >= 0) return "low";
    return "negative";
  }

  function shortCurrency(amount: number): string {
    if (Math.abs(amount) >= 1_000_000) {
      return `$${(amount / 1_000_000).toFixed(1)}M`;
    }
    if (Math.abs(amount) >= 1_000) {
      return `$${(amount / 1_000).toFixed(1)}K`;
    }
    return formatCurrency(amount);
  }

  // ── Product popover state ──
  let hoveredProduct: OpportunityProduct | null = null;
  let popoverX = 0;
  let popoverY = 0;
  let popoverTimeout: ReturnType<typeof setTimeout> | null = null;

  // ── Timeline entry popover state ──
  let hoveredEntry: TimelineEntry | null = null;
  let entryPopoverX = 0;
  let entryPopoverY = 0;
  let entryPopoverTimeout: ReturnType<typeof setTimeout> | null = null;
  let timelineSectionEl: HTMLElement | null = null;

  function showEntryPopover(e: MouseEvent, entry: TimelineEntry) {
    if (entry.kind !== "activity" || !entry.activity) return;
    if (entryPopoverTimeout) clearTimeout(entryPopoverTimeout);
    hoveredEntry = entry;
    const sectionRect = timelineSectionEl?.getBoundingClientRect();
    const entryRect = (e.currentTarget as HTMLElement).getBoundingClientRect();
    entryPopoverX = sectionRect ? sectionRect.left : entryRect.left;
    entryPopoverY = entryRect.top - 8;
  }

  function hideEntryPopover() {
    entryPopoverTimeout = setTimeout(() => {
      hoveredEntry = null;
    }, 150);
  }

  function keepEntryPopover() {
    if (entryPopoverTimeout) clearTimeout(entryPopoverTimeout);
  }

  function showPopover(e: MouseEvent, product: OpportunityProduct) {
    if (popoverTimeout) clearTimeout(popoverTimeout);
    hoveredProduct = product;
    const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
    popoverX = rect.left;
    popoverY = rect.top - 4;
  }

  function hidePopover() {
    popoverTimeout = setTimeout(() => {
      hoveredProduct = null;
    }, 150);
  }

  function keepPopover() {
    if (popoverTimeout) clearTimeout(popoverTimeout);
  }

  function productMarginPct(p: OpportunityProduct): string {
    if (!p.cost || p.cost === 0) return "—";
    return ((((p.revenue ?? 0) - p.cost) / p.cost) * 100).toFixed(1) + "%";
  }
</script>

<div class="overview-tab">
  <!-- ═══ Pipeline Banner ═══ -->
  <div class="ov-pipeline-banner">
    <div class="ov-pipeline-stages"></div>
  </div>

  <!-- ═══ Financial KPI Strip ═══ -->
  <div class="ov-kpi-strip">
    <div class="ov-kpi-card primary">
      <span class="ov-kpi-label">Revenue</span>
      <span class="ov-kpi-value">{formatCurrency(totalRevenue)}</span>
      <span class="ov-kpi-sub"
        >{activeProducts.length} line item{activeProducts.length !== 1
          ? "s"
          : ""}</span
      >
    </div>
    {#if canViewCost}
      <div class="ov-kpi-card">
        <span class="ov-kpi-label">Cost</span>
        <span class="ov-kpi-value">{formatCurrency(totalCost)}</span>
      </div>
    {/if}
    {#if canViewMargin}
      <div class="ov-kpi-card">
        <span class="ov-kpi-label">Margin</span>
        <span class="ov-kpi-value {marginHealthColor(marginPct)}"
          >{formatCurrency(totalMargin)}</span
        >
        <span class="ov-kpi-pct {marginHealthColor(marginPct)}"
          >{marginPct.toFixed(0)}%</span
        >
      </div>
    {/if}
    {#if totalTax > 0}
      <div class="ov-kpi-card">
        <span class="ov-kpi-label">Sales Tax</span>
        <span class="ov-kpi-value">{formatCurrency(totalTax)}</span>
      </div>
    {/if}
    <div class="ov-kpi-card accent">
      <span class="ov-kpi-label">Total</span>
      <span class="ov-kpi-value">{formatCurrency(grandTotal)}</span>
    </div>
    {#if hasCancellations}
      <div class="ov-kpi-card cancelled-kpi">
        <span class="ov-kpi-label">Cancelled</span>
        <span class="ov-kpi-value">
          {fullyCancelled.length + partiallyCancelled.length}
        </span>
        <span class="ov-kpi-sub">
          {#if fullyCancelled.length > 0}{fullyCancelled.length} full{/if}{#if fullyCancelled.length > 0 && partiallyCancelled.length > 0},
          {/if}{#if partiallyCancelled.length > 0}{partiallyCancelled.length} partial{/if}
        </span>
      </div>
    {/if}
  </div>

  <!-- ═══ Two-column layout: Timeline + Forecast ═══ -->
  <div class="ov-main-grid">
    <!-- Left: Timeline -->
    <div class="ov-section ov-timeline-section" bind:this={timelineSectionEl}>
      <h3 class="ov-section-title">
        <svg
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          width="15"
          height="15"
        >
          <circle cx="12" cy="12" r="10" /><polyline
            points="12 6 12 12 16 14"
          />
        </svg>
        Timeline
        {#if ageDays !== null}
          <span class="ov-age-badge">Age: {ageDays}d</span>
        {/if}
      </h3>
      {#if timeline.length > 0}
        <div class="ov-timeline">
          {#each visibleTimeline as entry, i}
            {#if timelineCollapsed && i === TIMELINE_EDGE}
              <!-- Collapsed gap -->
              <button
                class="ov-tl-gap-btn"
                on:click={() => dispatch("switchTab", "Activity")}
                title="View all in Activity tab"
              >
                <span class="ov-gap-pill">{hiddenCount} more events</span>
                <svg
                  class="ov-gap-arrow"
                  viewBox="0 0 16 16"
                  width="12"
                  height="12"
                  fill="none"
                  stroke="currentColor"
                  stroke-width="2"><path d="M6 3l5 5-5 5" /></svg
                >
              </button>
            {/if}
            <div
              class="ov-tl-entry"
              on:mouseenter={(e) => showEntryPopover(e, entry)}
              on:mouseleave={hideEntryPopover}
              role="listitem"
            >
              <!-- Connector -->
              <div class="ov-tl-connector">
                <div
                  class="ov-tl-dot {entry.kind === 'activity'
                    ? (entry.dotClass ?? 'ov-dot-default')
                    : 'ov-tl-dot-milestone'}"
                  class:ov-tl-dot-highlight={entry.highlight &&
                    entry.kind !== "activity"}
                >
                  {#if entry.kind === "activity"}
                    <svg
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      width="12"
                      height="12"
                    >
                      <path d={activityIcon(entry.label)} />
                    </svg>
                  {:else}
                    <svg
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      width="12"
                      height="12"
                    >
                      <circle cx="12" cy="12" r="10" /><polyline
                        points="12 6 12 12 16 14"
                      />
                    </svg>
                  {/if}
                </div>
                {#if i < visibleTimeline.length - 1 && !(timelineCollapsed && i === TIMELINE_EDGE - 1)}
                  <div class="ov-tl-line"></div>
                {/if}
              </div>
              <!-- Content -->
              <div class="ov-tl-body">
                {#if entry.kind === "activity" && entry.activity}
                  {@const act = entry.activity}
                  {@const open =
                    entry.closed != null
                      ? !entry.closed
                      : isOpenActivity(act)}
                  <!-- Header row: badges -->
                  <div class="at-content-header">
                    <span
                      class="at-type-badge {activityBadgeClass(entry.label)}"
                      >{entry.label}</span
                    >
                    {#if open}
                      <span class="at-open-badge">Open</span>
                    {/if}
                  </div>
                  <!-- Meta row: user + timestamp only -->
                  <div class="at-meta ov-tl-meta">
                    <span
                      class="at-user"
                      class:at-system={isSystemActivity(act)}
                    >
                      {#if isSystemActivity(act)}
                        <svg
                          viewBox="0 0 24 24"
                          fill="none"
                          stroke="currentColor"
                          stroke-width="2"
                          width="11"
                          height="11"
                        >
                          <rect
                            x="2"
                            y="3"
                            width="20"
                            height="14"
                            rx="2"
                            ry="2"
                          /><line x1="8" y1="21" x2="16" y2="21" /><line
                            x1="12"
                            y1="17"
                            x2="12"
                            y2="21"
                          />
                        </svg>
                      {:else}
                        <svg
                          viewBox="0 0 24 24"
                          fill="none"
                          stroke="currentColor"
                          stroke-width="2"
                          width="11"
                          height="11"
                        >
                          <path
                            d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"
                          /><circle cx="12" cy="7" r="4" />
                        </svg>
                      {/if}
                      {assignedDisplay(act)}
                    </span>
                    {#if act.cwDateEntered}
                      <span class="at-timestamp"
                        >{formatDateTime(act.cwDateEntered)}</span
                      >
                    {:else if act.dateStart}
                      <span class="at-timestamp"
                        >{formatDateTime(act.dateStart)}</span
                      >
                    {/if}
                  </div>
                {:else}
                  <!-- Milestone entry -->
                  <span
                    class="ov-tl-milestone"
                    class:ov-tl-milestone-highlight={entry.highlight}
                    >{entry.label}</span
                  >
                  <span class="ov-tl-date">{formatDate(entry.date)}</span>
                {/if}
              </div>
            </div>
          {/each}
        </div>
      {:else}
        <p class="ov-empty-note">No timeline events yet.</p>
      {/if}

      <!-- Timeline entry popover -->
      {#if hoveredEntry && hoveredEntry.activity}
        {@const pAct = hoveredEntry.activity}
        {@const pTransition = parseStatusTransition(pAct.notes)}
        {@const pOpen =
          hoveredEntry.closed != null
            ? !hoveredEntry.closed
            : isOpenActivity(pAct)}
        <div
          class="ov-entry-popover"
          style="top: {entryPopoverY}px; left: {entryPopoverX}px;"
          on:mouseenter={keepEntryPopover}
          on:mouseleave={hideEntryPopover}
          role="tooltip"
        >
          <!-- Header -->
          <div class="at-content-header">
            <span
              class="at-type-badge {activityBadgeClass(hoveredEntry.label)}"
              >{hoveredEntry.label}</span
            >
            {#if pTransition}
              <span class="at-transition-pill">
                <span class="at-transition-from">{pTransition.from}</span>
                <svg
                  viewBox="0 0 24 24"
                  fill="none"
                  stroke="currentColor"
                  stroke-width="2"
                  width="10"
                  height="10"
                >
                  <line x1="5" y1="12" x2="19" y2="12" /><polyline
                    points="12 5 19 12 12 19"
                  />
                </svg>
                <span class="at-transition-to">{pTransition.to}</span>
              </span>
            {/if}
            {#if pOpen}
              <span class="at-open-badge">Open</span>
            {/if}
          </div>
          <!-- Name -->
          {#if pAct.name}
            <p class="at-name">{pAct.name.replace(/^\[Workflow\]\s*/, "")}</p>
          {/if}
          <!-- Notes -->
          {#if pAct.notes}
            <p class="at-notes">{pAct.notes}</p>
          {/if}
          <!-- Meta -->
          <div class="at-meta">
            <span class="at-user" class:at-system={isSystemActivity(pAct)}>
              {#if isSystemActivity(pAct)}
                <svg
                  viewBox="0 0 24 24"
                  fill="none"
                  stroke="currentColor"
                  stroke-width="2"
                  width="12"
                  height="12"
                >
                  <rect x="2" y="3" width="20" height="14" rx="2" ry="2" /><line
                    x1="8"
                    y1="21"
                    x2="16"
                    y2="21"
                  /><line x1="12" y1="17" x2="12" y2="21" />
                </svg>
              {:else}
                <svg
                  viewBox="0 0 24 24"
                  fill="none"
                  stroke="currentColor"
                  stroke-width="2"
                  width="12"
                  height="12"
                >
                  <path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2" /><circle
                    cx="12"
                    cy="7"
                    r="4"
                  />
                </svg>
              {/if}
              {assignedDisplay(pAct)}
            </span>
            {#if pAct.cwDateEntered}
              <span class="at-timestamp">{formatDateTime(pAct.cwDateEntered)}</span>
            {:else if pAct.dateStart}
              <span class="at-timestamp">{formatDateTime(pAct.dateStart)}</span>
            {/if}
            {#if hoveredEntry.closedAt}
              <span class="at-timestamp at-closed-at"
                >Closed: {formatDateTime(hoveredEntry.closedAt)}</span
              >
            {:else if pAct.closedAt}
              <span class="at-timestamp at-closed-at"
                >Closed: {formatDateTime(pAct.closedAt)}</span
              >
            {:else if pAct.dateEnd}
              <span class="at-timestamp at-closed-at"
                >Closed: {formatDateTime(pAct.dateEnd)}</span
              >
            {/if}
          </div>
          <!-- Quote link -->
          {#if hoveredEntry.quoteId && hoveredEntry.label === "Quote Generated"}
            <button
              class="at-quote-link"
              on:click={() =>
                hoveredEntry?.quoteId &&
                dispatch("viewQuote", hoveredEntry.quoteId)}
              title="View quote"
            >
              <svg
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                width="13"
                height="13"
              >
                <path
                  d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"
                />
                <polyline points="14 2 14 8 20 8" />
              </svg>
              <span class="at-quote-link-label">{hoveredEntry.quoteId}</span>
              <svg
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                width="11"
                height="11"
                class="at-quote-link-arrow"
              >
                <line x1="5" y1="12" x2="19" y2="12" /><polyline
                  points="12 5 19 12 12 19"
                />
              </svg>
            </button>
          {/if}
        </div>
      {/if}

      <!-- Quick Stats under Timeline -->
      <div class="ov-quick-stats">
        <div class="ov-quick-stat">
          <svg
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
            width="14"
            height="14"
          >
            <path
              d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"
            /><polyline points="14 2 14 8 20 8" />
          </svg>
          <span>{notes.length} Note{notes.length !== 1 ? "s" : ""}</span>
        </div>
        <div class="ov-quick-stat">
          <svg
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
            width="14"
            height="14"
          >
            <path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2" /><circle
              cx="9"
              cy="7"
              r="4"
            />
          </svg>
          <span
            >{contacts.length} Contact{contacts.length !== 1 ? "s" : ""}</span
          >
        </div>
        {#if opportunity?.source}
          <div class="ov-quick-stat">
            <svg
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              width="14"
              height="14"
            >
              <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" /><circle
                cx="12"
                cy="12"
                r="3"
              />
            </svg>
            <span>{opportunity.source}</span>
          </div>
        {/if}
      </div>
    </div>

    <!-- Right: Condensed Forecast -->
    <div class="ov-section ov-forecast-section">
      <h3 class="ov-section-title">
        <svg
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          width="15"
          height="15"
        >
          <path
            d="M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 003 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0021 16z"
          />
          <polyline points="3.27 6.96 12 12.01 20.73 6.96" /><line
            x1="12"
            y1="22.08"
            x2="12"
            y2="12"
          />
        </svg>
        Forecast Summary
      </h3>

      {#if topProducts.length > 0}
        <!-- Top Products mini-table -->
        <div class="ov-forecast-table-wrap">
          <table class="ov-forecast-table">
            <thead>
              <tr>
                <th class="col-product">Product</th>
                <th class="col-revenue">Revenue</th>
                {#if canViewMargin}
                  <th class="col-margin">Margin</th>
                {/if}
              </tr>
            </thead>
            <tbody>
              {#each topProducts as p}
                <tr
                  class:ov-row-cancelled-full={p.cancellationType === "full"}
                  class:ov-row-cancelled-partial={p.cancellationType ===
                    "partial"}
                  on:mouseenter={(e) => showPopover(e, p)}
                  on:mouseleave={hidePopover}
                  on:click={() => dispatch("selectProduct", p.id)}
                  class="ov-forecast-row-clickable"
                >
                  <td class="col-product">
                    <span class="ov-product-inline">
                      <span
                        class="ov-qty-badge"
                        class:partial={p.cancellationType === "partial"}
                        class:cancelled={p.cancellationType === "full"}
                      >
                        {#if p.cancellationType === "partial"}
                          {effectiveQty(p)}<span class="ov-qty-orig"
                            >/{p.quantity}</span
                          >
                        {:else}
                          {p.quantity ?? "—"}
                        {/if}
                      </span>
                      <span class="ov-product-id"
                        >{p.catalogItem?.identifier ?? "—"}</span
                      >
                      {#if p.productDescription}
                        <span class="ov-product-desc"
                          >{p.productDescription}</span
                        >
                      {/if}
                      {#if p.cancellationType === "full"}
                        <span class="ov-cancel-badge full">Cancelled</span>
                      {:else if p.cancellationType === "partial"}
                        <span class="ov-cancel-badge partial">Partial</span>
                      {/if}
                    </span>
                  </td>
                  <td class="col-revenue">{formatCurrency(p.revenue)}</td>
                  {#if canViewMargin}
                    <td class="col-margin">
                      {#if p.cost && p.cost > 0}
                        <span
                          class="ov-margin-badge {marginHealthColor(
                            ((p.revenue - (p.cost ?? 0)) / (p.cost || 1)) * 100,
                          )}"
                        >
                          {(
                            ((p.revenue - (p.cost ?? 0)) / (p.cost || 1)) *
                            100
                          ).toFixed(0)}%
                        </span>
                      {:else}
                        <span class="ov-margin-badge neutral">—</span>
                      {/if}
                    </td>
                  {/if}
                </tr>
              {/each}
            </tbody>
            <tfoot>
              <tr>
                <td class="col-product"><strong>Subtotal</strong></td>
                <td class="col-revenue"
                  ><strong>{formatCurrency(totalRevenue)}</strong></td
                >
                {#if canViewMargin}
                  <td class="col-margin">
                    <span
                      class="ov-margin-badge {marginHealthColor(marginPct)}"
                    >
                      {marginPct.toFixed(0)}%
                    </span>
                  </td>
                {/if}
              </tr>
            </tfoot>
          </table>
          <!-- Product hover popover -->
          {#if hoveredProduct}
            <div
              class="ov-product-popover"
              style="top: {popoverY}px; left: {popoverX}px;"
              on:mouseenter={keepPopover}
              on:mouseleave={hidePopover}
              role="tooltip"
            >
              <div class="ov-popover-header">
                <span class="ov-popover-id"
                  >{hoveredProduct.catalogItem?.identifier ?? "—"}</span
                >
              </div>
              {#if hoveredProduct.productDescription}
                <div class="ov-popover-desc">
                  {hoveredProduct.productDescription}
                </div>
              {/if}
              {#if hoveredProduct.forecastDescription && hoveredProduct.forecastDescription !== hoveredProduct.productDescription}
                <div class="ov-popover-field">
                  <span class="ov-popover-label">Forecast</span>
                  <span class="ov-popover-value"
                    >{hoveredProduct.forecastDescription}</span
                  >
                </div>
              {/if}
              {#if hoveredProduct.forecastType}
                <div class="ov-popover-field">
                  <span class="ov-popover-label">Type</span>
                  <span class="ov-popover-value"
                    >{hoveredProduct.forecastType}</span
                  >
                </div>
              {/if}
              {#if hoveredProduct.productClass}
                <div class="ov-popover-field">
                  <span class="ov-popover-label">Class</span>
                  <span class="ov-popover-value"
                    >{hoveredProduct.productClass}</span
                  >
                </div>
              {/if}
              <div class="ov-popover-financials">
                <div class="ov-popover-fin-item">
                  <span class="ov-popover-fin-label">Qty</span>
                  <span class="ov-popover-fin-value"
                    >{hoveredProduct.quantity ?? "—"}</span
                  >
                </div>
                <div class="ov-popover-fin-item">
                  <span class="ov-popover-fin-label">Revenue</span>
                  <span class="ov-popover-fin-value"
                    >{formatCurrency(hoveredProduct.revenue)}</span
                  >
                </div>
                {#if canViewCost}
                  <div class="ov-popover-fin-item">
                    <span class="ov-popover-fin-label">Cost</span>
                    <span class="ov-popover-fin-value"
                      >{formatCurrency(hoveredProduct.cost)}</span
                    >
                  </div>
                {/if}
                {#if canViewMargin}
                  <div class="ov-popover-fin-item">
                    <span class="ov-popover-fin-label">Margin</span>
                    <span class="ov-popover-fin-value"
                      >{formatCurrency(hoveredProduct.margin)}</span
                    >
                  </div>
                  <div class="ov-popover-fin-item">
                    <span class="ov-popover-fin-label">Margin %</span>
                    <span class="ov-popover-fin-value"
                      >{productMarginPct(hoveredProduct)}</span
                    >
                  </div>
                {/if}
              </div>
              {#if hoveredProduct.cancellationType}
                <div
                  class="ov-popover-cancel {hoveredProduct.cancellationType ===
                  'full'
                    ? 'ov-popover-cancel--full'
                    : ''}"
                >
                  {hoveredProduct.cancellationType === "partial"
                    ? "Partially Cancelled"
                    : "Cancelled"}
                  {#if hoveredProduct.quantityCancelled}
                    — {hoveredProduct.quantityCancelled} unit{hoveredProduct.quantityCancelled !==
                    1
                      ? "s"
                      : ""}
                  {/if}
                </div>
              {/if}
              {#if hoveredProduct.recurringFlag}
                <div class="ov-popover-flag">Recurring</div>
              {/if}
            </div>
          {/if}

          {#if activeProducts.length > 15}
            <div class="ov-forecast-more">
              +{activeProducts.length - 15} more item{activeProducts.length -
                15 !==
              1
                ? "s"
                : ""}
            </div>
          {/if}
        </div>

        <!-- Class Breakdown -->
        {#if classBreakdown.length > 1}
          <div class="ov-class-breakdown">
            <span class="ov-class-breakdown-title">By Product Class</span>
            <div class="ov-class-bars">
              {#each classBreakdown as cls}
                <div class="ov-class-row">
                  <span class="ov-class-name">{cls.name}</span>
                  <div class="ov-class-bar-track">
                    <div
                      class="ov-class-bar-fill"
                      style="width: {totalRevenue > 0
                        ? (cls.revenue / totalRevenue) * 100
                        : 0}%"
                    ></div>
                  </div>
                  <span class="ov-class-amount"
                    >{shortCurrency(cls.revenue)}</span
                  >
                </div>
              {/each}
            </div>
          </div>
        {/if}
      {:else}
        <p class="ov-empty-note">No products on this opportunity yet.</p>
      {/if}
    </div>
  </div>
</div>
