/**
 * Calendar-task integration queries — calendar-task-creation (wave-9 leaf 2).
 *
 * Links tasks to calendar events via tasks.external_id = eventId + tasks.source = 'manual'.
 * No schema migration required — existing columns carry the relationship.
 *
 * createTaskFromCalendarEvent: creates a task pre-filled from event data and resolves
 *   the tenant's first (lowest-position) global task status as the default column.
 *
 * getCalendarEventTasks: lists tasks whose external_id matches the eventId.
 */
import { eq, and, asc, isNull } from 'drizzle-orm'
import type { Db } from '../client'
import { tasks, taskStatuses } from '../schema/tasks'
import { auditLog } from './_audit-forward'
import { assertTenantOwnsOrThrow, assertActiveTenantAssignee } from './tenant-guards'
import { positionBetween } from '../lib/fractional-index'
import type { TaskObject } from '@zync/types'

// ── Serializer (minimal — mirrors tasks.ts) ────────────────────────────────────

function serializeTask(row: typeof tasks.$inferSelect): TaskObject {
  return {
    id: row.id,
    tenant_id: row.tenantId,
    project_id: row.projectId ?? null,
    status_id: row.statusId,
    title: row.title,
    description: row.description ?? null,
    priority: row.priority as TaskObject['priority'],
    assignee_id: row.assigneeId ?? null,
    reporter_id: row.reporterId,
    due_date: row.dueDate ?? null,
    estimated_hours:
      row.estimatedHours !== null && row.estimatedHours !== undefined
        ? parseFloat(String(row.estimatedHours))
        : null,
    source: row.source as TaskObject['source'],
    external_id: row.externalId ?? null,
    position: parseFloat(String(row.position)),
    labels: [],
    created_at: row.createdAt.toISOString(),
    updated_at: row.updatedAt.toISOString(),
  }
}

// ── createTaskFromCalendarEvent ────────────────────────────────────────────────

export interface CreateTaskFromEventInput {
  title: string
  priority?: 'low' | 'medium' | 'high' | 'urgent'
  assigneeId?: string | null
  dueDate?: string | null // ISO date 'YYYY-MM-DD'
}

export async function createTaskFromCalendarEvent(
  db: Db,
  tenantId: string,
  userId: string,
  eventId: string,
  taskData: CreateTaskFromEventInput,
): Promise<TaskObject> {
  return db.transaction(async (tx) => {
    // Resolve default status: first global (project_id IS NULL) status by position
    const [defaultStatus] = await tx
      .select()
      .from(taskStatuses)
      .where(and(eq(taskStatuses.tenantId, tenantId), isNull(taskStatuses.projectId)))
      .orderBy(asc(taskStatuses.position))
      .limit(1)

    if (!defaultStatus) {
      throw new Error('No task statuses configured for this tenant')
    }

    // Append to end of that column
    const [maxRow] = await tx
      .select({ pos: tasks.position })
      .from(tasks)
      .where(and(eq(tasks.tenantId, tenantId), eq(tasks.statusId, defaultStatus.id)))
      .orderBy(asc(tasks.position))
      .limit(1)

    const position = positionBetween(
      maxRow ? parseFloat(String(maxRow.pos)) : null,
      null,
    )

    assertTenantOwnsOrThrow(
      'assignee_id',
      await assertActiveTenantAssignee(tx, tenantId, taskData.assigneeId),
    )

    const [row] = await tx
      .insert(tasks)
      .values({
        tenantId,
        statusId: defaultStatus.id,
        title: taskData.title,
        priority: taskData.priority ?? 'medium',
        assigneeId: taskData.assigneeId ?? null,
        reporterId: userId,
        dueDate: taskData.dueDate ?? null,
        source: 'manual',
        externalId: eventId,
        position: String(position),
      })
      .returning()

    if (!row) throw new Error('Task insert failed')

    await tx.insert(auditLog).values({
      tenantId,
      actorId: userId,
      actorType: 'user',
      entityType: 'task',
      entityId: row.id,
      action: 'task.created',
      changes: null,
    })

    return serializeTask(row)
  })
}

// ── getCalendarEventTasks ──────────────────────────────────────────────────────

export async function getCalendarEventTasks(
  db: Db,
  tenantId: string,
  eventId: string,
): Promise<TaskObject[]> {
  const rows = await db
    .select()
    .from(tasks)
    .where(
      and(
        eq(tasks.tenantId, tenantId),
        eq(tasks.externalId, eventId),
        eq(tasks.source, 'manual'),
      ),
    )
    .orderBy(asc(tasks.createdAt))

  return rows.map(serializeTask)
}
