// Pure transform on the `/api/v1/statuses/{id}/context` `descendants` wire
// shape. The Halflight server already returns rows in DFS preorder with
// per-level self-reply promotion (audit H3-fix-A: at each parent, the
// author's continuation subtree comes before non-self subtrees so the OP's
// thread reads top-to-bottom under each branch). This builder rebuilds the
// parent→children tree in a single linear pass — no sort, no recursion —
// and surfaces:
//
//   - `roots`: top-level replies to the anchor, in server preorder.
//   - `preorder`: every node depth-annotated, in server preorder. Consumed
//     by `flattenWithDepth` to drive the per-row stripe + bounded indent
//     visualization (`src/components/comments/threadStyle.ts`).
//   - `hasChildrenById`: cheap membership lookup the row renderer can use
//     to decide whether to surface child-related affordances.
//
// Visibility-filtered mid-tree rows (the server's `StatusVisibilityResolver`
// runs ahead of the walk, and can drop a parent while its children survive)
// are promoted to the top via the orphan bucket so they don't silently
// disappear from the rendered list.
//
// No I/O, no React. Single render mode for the whole user base — there is
// no longer a flat-vs-nested split or a visual-cap collapse; depth alone
// drives the stripe + indent at the row level.

import type { Status } from 'src/lib/api-types'

export type ThreadNode = {
  status: Status
  // 0 for direct replies to the anchor, 1 for replies-to-replies, etc.
  // Capped by the server's DESCENDANTS_DEPTH_LIMIT=20 by construction.
  depth: number
  // Replies to this node, in server preorder (per-level self-reply
  // promotion preserved — the OP's continuation subtree surfaces first
  // under each parent).
  children: ThreadNode[]
}

export type ThreadShape = {
  roots: ThreadNode[]
  // Flat preorder traversal, depth-annotated. Same row order as the
  // server's `descendants`; depth attached for indentation rendering on
  // the otherwise-flat list. Orphans (parent dropped by the server's
  // visibility filter) appear at the tail, all at depth 0.
  preorder: ThreadNode[]
  hasChildrenById: Map<string, boolean>
}

export function buildThreadTree(descendants: Status[], anchorId: string): ThreadShape {
  const byId = new Map<string, ThreadNode>()
  const roots: ThreadNode[] = []
  const orphans: ThreadNode[] = []
  const hasChildrenById = new Map<string, boolean>()

  for (const s of descendants) {
    byId.set(s.id, { status: s, depth: 0, children: [] })
  }

  // Single pass: server already emits DFS preorder, so the parent of any
  // non-root row is guaranteed to appear earlier in the list — depth and
  // children pointers both resolve in the same walk.
  for (const s of descendants) {
    const node = byId.get(s.id)!
    const parentId = s.in_reply_to_id
    if (parentId === anchorId) {
      roots.push(node)
      continue
    }
    if (parentId && byId.has(parentId)) {
      const parent = byId.get(parentId)!
      parent.children.push(node)
      node.depth = parent.depth + 1
      hasChildrenById.set(parentId, true)
      continue
    }
    if (__DEV__) {
      console.warn(
        `[thread-tree] orphan reply ${s.id}: parent ${parentId} not in /context`
      )
    }
    orphans.push(node)
  }

  // Roots first (in preorder), orphans appended at the tail. Orphans stay
  // visible at depth 0 — losing them silently to a visibility-filter race
  // would be the worse failure mode.
  const preorder: ThreadNode[] = []
  for (const root of roots) appendPreorder(root, preorder)
  for (const orphan of orphans) appendPreorder(orphan, preorder)

  return { roots: [...roots, ...orphans], preorder, hasChildrenById }
}

function appendPreorder(node: ThreadNode, out: ThreadNode[]): void {
  out.push(node)
  for (const child of node.children) appendPreorder(child, out)
}

// Depth-annotated DFS preorder walk. Companion to `buildThreadTree.roots`
// — feeds `CommentThreadList`'s renderItem with `{ comment, depth }` so
// each row can spread `threadRowStyle(depth)` without knowing about its
// siblings.
export function flattenWithDepth(
  roots: ThreadNode[]
): { comment: Status; depth: number }[] {
  const rows: { comment: Status; depth: number }[] = []
  const walk = (node: ThreadNode) => {
    rows.push({ comment: node.status, depth: node.depth })
    for (const child of node.children) walk(child)
  }
  for (const root of roots) walk(root)
  return rows
}
