import { createLogger } from '@sim/logger'
import { generateId } from '@sim/utils/id'
import type { RequestTraceV1Outcome as RequestTraceOutcome } from '@/lib/copilot/generated/request-trace-v1'
import {
  RequestTraceV1Outcome,
  RequestTraceV1SpanStatus,
} from '@/lib/copilot/generated/request-trace-v1'
import { CopilotTransport } from '@/lib/copilot/generated/trace-attribute-values-v1'
import type { CopilotLifecycleOptions } from '@/lib/copilot/request/lifecycle/run'
import { runCopilotLifecycle } from '@/lib/copilot/request/lifecycle/run'
import { withCopilotOtelContext } from '@/lib/copilot/request/otel'
import { TraceCollector } from '@/lib/copilot/request/trace'
import type { OrchestratorResult } from '@/lib/copilot/request/types'

const logger = createLogger('CopilotHeadlessLifecycle')

export async function runHeadlessCopilotLifecycle(
  requestPayload: Record<string, unknown>,
  options: CopilotLifecycleOptions
): Promise<OrchestratorResult> {
  const simRequestId =
    typeof options.simRequestId === 'string' && options.simRequestId.length > 0
      ? options.simRequestId
      : typeof requestPayload.messageId === 'string' && requestPayload.messageId.length > 0
        ? requestPayload.messageId
        : generateId()
  const trace = new TraceCollector()
  const requestSpan = trace.startSpan('Headless Sim Agent Request', 'request', {
    route: options.goRoute,
    workflowId: options.workflowId,
    workspaceId: options.workspaceId,
    chatId: options.chatId,
  })

  let result: OrchestratorResult | undefined
  let outcome: RequestTraceOutcome = RequestTraceV1Outcome.error

  return withCopilotOtelContext(
    {
      requestId: simRequestId,
      route: options.goRoute,
      chatId: options.chatId,
      workflowId: options.workflowId,
      executionId: options.executionId,
      runId: options.runId,
      transport: CopilotTransport.Headless,
    },
    async (otelContext) => {
      try {
        result = await runCopilotLifecycle(requestPayload, {
          ...options,
          trace,
          simRequestId,
          otelContext,
        })
        outcome = result.success
          ? RequestTraceV1Outcome.success
          : options.abortSignal?.aborted || result.cancelled
            ? RequestTraceV1Outcome.cancelled
            : RequestTraceV1Outcome.error
        return result
      } catch (error) {
        outcome = options.abortSignal?.aborted
          ? RequestTraceV1Outcome.cancelled
          : RequestTraceV1Outcome.error
        throw error
      } finally {
        trace.endSpan(
          requestSpan,
          outcome === RequestTraceV1Outcome.success
            ? RequestTraceV1SpanStatus.ok
            : outcome === RequestTraceV1Outcome.cancelled
              ? RequestTraceV1SpanStatus.cancelled
              : RequestTraceV1SpanStatus.error
        )
      }
    }
  )
}
