/**
 * Fractional-indexing helpers — tasks-board-engine.
 *
 * Positions within a Kanban column are stored as NUMERIC (Postgres) / number (JS).
 * Fractional indexing allows efficient reordering without renumbering the whole column:
 *   - Drop between 1.0 and 2.0 → position 1.5
 *   - Repeatedly halving narrows the gap; when gap < 0.001 → rebalance
 *
 * positionBetween(before, after):
 *   - both null  → 1 (first card in empty column)
 *   - before=null (prepend) → after - 1
 *   - after=null  (append)  → before + 1
 *   - both set   → midpoint
 *
 * needsRebalance: true when gap would fall below threshold.
 *
 * rebalanceColumn: renumbers all tasks in a status column to contiguous integers
 * (1, 2, 3 …) preserving visual order.
 */
import { eq, and, asc } from 'drizzle-orm'
import type { Db, DbTx } from '../client'
import { tasks } from '../schema/tasks'

const REBALANCE_THRESHOLD = 0.001

export function positionBetween(before: number | null, after: number | null): number {
  if (before === null && after === null) return 1
  if (before === null) return (after as number) - 1
  if (after === null) return before + 1
  return (before + after) / 2
}

export function needsRebalance(before: number | null, after: number | null): boolean {
  if (before === null || after === null) return false
  return Math.abs(after - before) < REBALANCE_THRESHOLD
}

/**
 * Renumber all tasks in (tenantId, statusId) to positions 1, 2, 3 …
 * preserving the current positional order.
 * Must be called inside a transaction to be atomic.
 */
export async function rebalanceColumn(
  tx: Db | DbTx,
  tenantId: string,
  statusId: string,
): Promise<void> {
  // Fetch all tasks in the column ordered by current position
  const rows = await tx
    .select({ id: tasks.id })
    .from(tasks)
    .where(and(eq(tasks.tenantId, tenantId), eq(tasks.statusId, statusId)))
    .orderBy(asc(tasks.position))

  // Update each task to its new contiguous integer position
  for (let i = 0; i < rows.length; i++) {
    const row = rows[i]
    if (!row) continue
    await tx
      .update(tasks)
      .set({ position: String(i + 1) })
      .where(and(eq(tasks.tenantId, tenantId), eq(tasks.id, row.id)))
  }
}
