<script lang="ts">
  import { createEventDispatcher, onMount } from "svelte";
  import { clientFetch } from "$lib/client-fetch";
  import type {
    WorkflowHistoryEntry,
    WorkflowTimeEntry,
    OpportunityActivity,
  } from "$lib/optima-api/modules/sales";
  import { formatDateTime } from "../types";

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

  export let opportunityId: string;
  export let activities: OpportunityActivity[] = [];

  let workflowHistory: WorkflowHistoryEntry[] = [];
  let isLoading = true;
  let loadError: string | null = null;

  onMount(() => {
    fetchHistory();
  });

  async function fetchHistory() {
    isLoading = true;
    loadError = null;
    try {
      const json = await clientFetch<{
        data: { activities: WorkflowHistoryEntry[] };
      }>(`/sales/opportunity/${opportunityId}/workflow/history`);
      workflowHistory = json.data?.activities ?? [];
    } catch (err) {
      loadError =
        err instanceof Error ? err.message : "Failed to load workflow history";
    } finally {
      isLoading = false;
    }
  }

  export function refresh() {
    fetchHistory();
  }

  /** Extract the Parent_Activity ID (custom field 50) */
  function getParentActivityId(activity: OpportunityActivity): number | null {
    const cf = activity.customFields?.find(
      (f) => f.id === 50 || f.caption === "Parent_Activity",
    );
    if (!cf?.value) return null;
    const parsed = parseInt(cf.value, 10);
    return isNaN(parsed) ? null : parsed;
  }

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

  /** Get an icon for the Optima_Type */
  function optimaTypeIcon(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-7zM9 12l2 2 4-4";
      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";
    }
  }

  /** CSS class for Optima_Type badge */
  function optimaTypeBadgeClass(type: string | null): string {
    switch (type) {
      case "Opportunity Created":
        return "at-type-created";
      case "Opportunity Setup":
        return "at-type-setup";
      case "Opportunity Review":
        return "at-type-review";
      case "Quote Sent":
        return "at-type-sent";
      case "Quote Confirmed":
        return "at-type-confirmed";
      case "Quote Sent & Confirmed":
        return "at-type-sent-confirmed";
      case "Revision":
        return "at-type-revision";
      case "Finalized":
        return "at-type-finalized";
      case "Converted":
        return "at-type-converted";
      case "Quote Generated":
        return "at-type-generated";
      default:
        return "at-type-default";
    }
  }

  /** Determine if an activity is system-generated (no assignTo or automation-generated) */
  function isSystemActivity(activity: OpportunityActivity): boolean {
    return !activity.assignTo?.name && !activity.cwEnteredBy;
  }

  /** Format the assigned user display */
  function assignedDisplay(activity: OpportunityActivity): string {
    if (isSystemActivity(activity)) return "System";
    return activity.assignTo?.name ?? activity.cwEnteredBy ?? "Unknown";
  }

  /** Check if activity is a status transition (has CW status change in notes) */
  function parseStatusTransition(
    notes: string | undefined,
  ): { from: string; to: string } | null {
    if (!notes) return null;
    // The workflow engine embeds status transitions in notes like: [StatusA → StatusB]
    const match = notes.match(/\[(\w+)\s*→\s*(\w+)\]/);
    if (match) return { from: match[1], to: match[2] };
    return null;
  }

  /** Check if activity is open (closed flag first, then status id, then dateEnd fallback) */
  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;
  }

  /** Check if activity is late (dateEnd > dueDate-equivalent) */
  function isLateActivity(_activity: OpportunityActivity): {
    late: boolean;
    days: number;
  } {
    // Activities use dateStart/dateEnd, not dueDate. Check if closed after scheduled end.
    return { late: false, days: 0 };
  }

  // ── Tree node types ───────────────────────────────────────────────────────

  type ActivityNode = {
    kind: "activity";
    item: WorkflowHistoryEntry;
    depth: number;
  };

  type TimeEntryNode = {
    kind: "timeEntry";
    entry: WorkflowTimeEntry;
    depth: number;
  };

  type TreeNode = ActivityNode | TimeEntryNode;

  /** Combine CW activities with workflow history into a unified timeline, sorted by creation date */
  $: timelineItems = (() => {
    let items: WorkflowHistoryEntry[];
    if (workflowHistory.length > 0) {
      items = workflowHistory;
    } else {
      items = (activities ?? []).map((a) => ({
        activity: a,
        optimaType: getOptimaType(a) ?? "",
        quoteId: null,
        parentActivityId: null,
        closed: null as unknown as boolean,
        closedAt: null,
        timeEntries: [],
      }));
    }
    // Sort by creation date (cwDateEntered or dateStart), newest first
    return items.slice().sort((a, b) => {
      const dateA = a.activity.cwDateEntered ?? a.activity.dateStart ?? "";
      const dateB = b.activity.cwDateEntered ?? b.activity.dateStart ?? "";
      return dateB.localeCompare(dateA);
    });
  })();

  /**
   * Build a flat tree interleaving time entries at the correct depth.
   *
   * Inverted tree: children and time entries appear ABOVE the activity they
   * belong to, so work done under a workflow step is visible before the step
   * itself in the timeline.
   *
   * Algorithm:
   *  1. Resolve parent-child relationships between activities using parentActivityId.
   *  2. For each activity, first recursively insert its child activities, then its
   *     time entries (sorted dateStart asc), then the activity node itself.
   */
  $: flatTree = (() => {
    // Map cwActivityId → WorkflowHistoryEntry
    const idToItem = new Map<number, WorkflowHistoryEntry>(
      timelineItems.map((item) => [item.activity.cwActivityId, item]),
    );

    // Build children map: parentCwId → child items
    const childrenMap = new Map<number, WorkflowHistoryEntry[]>();
    const roots: WorkflowHistoryEntry[] = [];

    for (const item of timelineItems) {
      const parentId = item.parentActivityId ?? null;
      if (parentId != null && idToItem.has(parentId)) {
        if (!childrenMap.has(parentId)) childrenMap.set(parentId, []);
        childrenMap.get(parentId)!.push(item);
      } else {
        roots.push(item);
      }
    }

    const flat: TreeNode[] = [];

    function insertActivity(item: WorkflowHistoryEntry, depth: number) {
      const cwId = item.activity.cwActivityId;

      // 1. Child activities first (inverted: children above parent)
      for (const child of childrenMap.get(cwId) ?? []) {
        insertActivity(child, depth + 1);
      }

      // 2. Time entries for this activity, sorted by dateStart asc
      const entries = (item.timeEntries ?? []).slice().sort((a, b) => {
        const da = a.dateStart ?? a.timeStart ?? "";
        const db = b.dateStart ?? b.timeStart ?? "";
        return da.localeCompare(db);
      });
      for (const entry of entries) {
        flat.push({ kind: "timeEntry", entry, depth: depth + 1 });
      }

      // 3. The activity node itself (below its children)
      flat.push({ kind: "activity", item, depth });
    }

    for (const root of roots) {
      insertActivity(root, 0);
    }

    return flat;
  })();
</script>

<div class="activity-tab">
  <div class="at-header">
    <h3 class="overview-section-title">
      <svg
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
        width="16"
        height="16"
      >
        <circle cx="12" cy="12" r="10" /><path d="M12 6v6l4 2" />
      </svg>
      Workflow Activity
    </h3>
    <button
      class="at-refresh-btn"
      on:click={fetchHistory}
      disabled={isLoading}
      title="Refresh"
    >
      <svg
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
        width="14"
        height="14"
        class:at-spinning={isLoading}
      >
        <polyline points="23 4 23 10 17 10" />
        <polyline points="1 20 1 14 7 14" />
        <path
          d="M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15"
        />
      </svg>
    </button>
  </div>

  {#if isLoading && timelineItems.length === 0}
    <div class="at-loading">
      <span class="wf-spinner"></span>
      <span>Loading activity history...</span>
    </div>
  {:else if loadError}
    <div class="at-error">
      <svg
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
        width="16"
        height="16"
      >
        <circle cx="12" cy="12" r="10" /><line
          x1="15"
          y1="9"
          x2="9"
          y2="15"
        /><line x1="9" y1="9" x2="15" y2="15" />
      </svg>
      <span>{loadError}</span>
    </div>
  {:else if timelineItems.length === 0}
    <div class="at-empty">
      <svg
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="1.5"
        width="32"
        height="32"
      >
        <circle cx="12" cy="12" r="10" /><path d="M12 6v6l4 2" />
      </svg>
      <p>No workflow activity yet.</p>
    </div>
  {:else}
    <div class="at-timeline">
      {#each flatTree as node, i (node.kind === "activity" ? `act-${node.item.activity.cwActivityId}-d${node.depth}` : `te-${node.entry.id}-d${node.depth}`)}
        {#if node.kind === "timeEntry"}
          {@const te = node.entry}
          {@const hasAbove = i > 0}
          {@const hasD1Above = i > 0 && flatTree[i - 1].depth >= 2}
          <div
            class="at-entry at-entry-time-entry"
            style="--at-depth: {node.depth}"
          >
            <div class="at-connector" data-depth="{node.depth}" class:at-has-above={hasAbove} class:at-has-d1-above={hasD1Above}>
              <div class="at-branch"></div>
              <div class="at-dot at-dot-time-entry">
                <!-- Clock icon -->
                <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>
              </div>
            </div>
            <div class="at-content">
              <div class="at-content-header">
                <span class="at-type-badge at-type-time-entry">Time Entry</span>
                {#if te.billableFlag}
                  <span class="at-open-badge">Billable</span>
                {/if}
              </div>
              {#if te.notes}
                <p class="at-notes">{te.notes}</p>
              {/if}
              <div class="at-meta">
                {#if te.memberId}
                  <span class="at-user">
                    <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>
                    {te.memberId}
                  </span>
                {/if}
                {#if te.actualHours != null}
                  <span class="at-timestamp">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="11" height="11">
                      <circle cx="12" cy="12" r="10" /><polyline points="12 6 12 12 16 14" />
                    </svg>
                    {te.actualHours}h
                  </span>
                {/if}
                {#if te.timeStart}
                  <span class="at-timestamp at-schedule-time">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="11" height="11">
                      <rect x="3" y="4" width="18" height="18" rx="2" ry="2" />
                      <line x1="16" y1="2" x2="16" y2="6" />
                      <line x1="8" y1="2" x2="8" y2="6" />
                      <line x1="3" y1="10" x2="21" y2="10" />
                    </svg>
                    {formatDateTime(te.timeStart)}{#if te.timeEnd}&nbsp;–&nbsp;{formatDateTime(te.timeEnd)}{/if}
                  </span>
                {:else if te.dateStart}
                  <span class="at-timestamp">{formatDateTime(te.dateStart)}</span>
                {/if}
              </div>
            </div>
          </div>
        {:else}
          {@const item = node.item}
          {@const act = item.activity}
          {@const transition = parseStatusTransition(act.notes)}
          {@const open = item.closed != null ? !item.closed : isOpenActivity(act)}
          {@const hasAbove = i > 0}
          {@const hasD1Above = i > 0 && flatTree[i - 1].depth >= 2}
          <div
            class="at-entry"
            class:at-entry-open={open}
            style="--at-depth: {node.depth}"
          >
            <!-- Timeline connector -->
            <div class="at-connector" data-depth="{node.depth}" class:at-has-above={hasAbove} class:at-has-d1-above={hasD1Above}>
              {#if node.depth > 0}
                <div class="at-branch"></div>
              {/if}
              <div
                class="at-dot"
                class:at-dot-open={open}
                class:at-dot-system={isSystemActivity(act)}
              >
                <svg
                  viewBox="0 0 24 24"
                  fill="none"
                  stroke="currentColor"
                  stroke-width="2"
                  width="12"
                  height="12"
                >
                  <path d={optimaTypeIcon(item.optimaType)} />
                </svg>
              </div>
              {#if node.depth === 0 && i < flatTree.length - 1}
                <div class="at-line"></div>
              {/if}
            </div>

            <!-- Entry content -->
            <div class="at-content">
              <div class="at-content-header">
                <!-- Optima type badge -->
                {#if item.optimaType}
                  <span
                    class="at-type-badge {optimaTypeBadgeClass(item.optimaType)}"
                  >
                    {item.optimaType}
                  </span>
                {/if}

                <!-- Status transition pill -->
                {#if transition}
                  <span class="at-transition-pill">
                    <span class="at-transition-from">{transition.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">{transition.to}</span>
                  </span>
                {/if}

                <!-- Open indicator -->
                {#if open}
                  <span class="at-open-badge">Open</span>
                {/if}
              </div>

              <!-- Activity name -->
              {#if act.name}
                <p class="at-name">{act.name}</p>
              {/if}

              <!-- Notes body -->
              {#if act.notes}
                <p class="at-notes">{act.notes}</p>
              {/if}

              <!-- Meta row -->
              <div class="at-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="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(act)}
                </span>

                {#if act.cwDateEntered && item.optimaType !== "Schedule Entry"}
                  <span class="at-timestamp"
                    >{formatDateTime(act.cwDateEntered)}</span
                  >
                {/if}

                {#if item.optimaType === "Schedule Entry" && (act.dateStart || act.dateEnd)}
                  <span class="at-timestamp at-schedule-time">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="11" height="11">
                      <rect x="3" y="4" width="18" height="18" rx="2" ry="2" />
                      <line x1="16" y1="2" x2="16" y2="6" />
                      <line x1="8" y1="2" x2="8" y2="6" />
                      <line x1="3" y1="10" x2="21" y2="10" />
                    </svg>
                    {#if act.dateStart}{formatDateTime(act.dateStart)}{/if}{#if act.dateStart && act.dateEnd}&nbsp;–&nbsp;{/if}{#if act.dateEnd}{formatDateTime(act.dateEnd)}{/if}
                  </span>
                {/if}

                {#if item.closedAt}
                  <span class="at-timestamp at-closed-at">
                    Closed: {formatDateTime(item.closedAt)}
                  </span>
                {:else if act.closedAt}
                  <span class="at-timestamp at-closed-at">
                    Closed: {formatDateTime(act.closedAt)}
                  </span>
                {:else if act.dateEnd && item.optimaType !== "Schedule Entry"}
                  <span class="at-timestamp at-closed-at">
                    Closed: {formatDateTime(act.dateEnd)}
                  </span>
                {/if}
              </div>

              <!-- Quote reference sub-item -->
              {#if item.quoteId && item.optimaType === "Quote Generated"}
                <button
                  class="at-quote-link"
                  on:click={() =>
                    item.quoteId && dispatch("viewQuote", item.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">{item.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>
          </div>
        {/if}
      {/each}
    </div>
  {/if}
</div>
