import { Effect } from "effect"
import type { MessageID, PartID, SessionID } from "@/session/schema"
import type { MessageV2 } from "@/session/message-v2"
import { iife } from "@/util/iife"

export namespace SaeeolSnapshotTrack {
  export const TIMEOUT_MS = iife(() => {
    const raw = process.env["SAEEOL_SNAPSHOT_TRACK_TIMEOUT_MS"]
    if (raw) {
      const parsed = Number(raw)
      if (Number.isFinite(parsed) && parsed > 0) return parsed
    }
    return 10_000
  })

  export const ANSWER_CONTINUE = "Continue with snapshots"
  export const ANSWER_DISABLE = "Disable for this project"

  /**
   * User-visible progress label injected into the live assistant message
   * while snapshot.track() is running. The leading `{spinner}` placeholder
   * is replaced at publish time with a rotating braille frame.
   */
  export const PROGRESS_INITIALIZING = "{spinner} Initializing snapshot…"

  export const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"] as const
  export const SPINNER_INTERVAL_MS = 120

  export const formatProgress = (template: string, frame: string): string =>
    template.replace("{spinner}", frame)

  export interface State {
    disabledForSession: boolean
    asked: boolean
  }

  export const makeState = (): State => ({
    disabledForSession: false,
    asked: false,
  })

  export type Answer = "continue" | "disable" | "dismissed"

  export interface Hooks {
    readonly ask: (input: { sessionID: SessionID }) => Promise<Answer>
    readonly persistDisable: () => Promise<void>
    readonly startProgress: (input: {
      sessionID: SessionID
      messageID: MessageID
      text: string
    }) => Promise<ProgressHandle | undefined>
    readonly updateProgress: (input: { handle: ProgressHandle; text: string }) => Promise<void>
    readonly endProgress: (input: { handle: ProgressHandle }) => Promise<void>
  }

  export type ProgressHandle = {
    readonly sessionID: SessionID
    readonly messageID: MessageID
    readonly partID: PartID
  }

  export interface WrapInput {
    readonly inner: Effect.Effect<string | undefined>
    readonly state: State
    readonly sessionID?: SessionID
    readonly messageID?: MessageID
    readonly hooks?: Hooks
    readonly timeoutMs?: number
    readonly progressDelayMs?: number
  }

  /**
   * Narrow typed view of the Session.Service methods used by defaultHooks.
   * Kept local to avoid a value-level import cycle with @/session/index.ts.
   */
  export interface SessionPartAPI {
    readonly updatePart: <T extends MessageV2.Part>(part: T) => Effect.Effect<T>
    readonly removePart: (
      input: { sessionID: SessionID; messageID: MessageID; partID: PartID },
    ) => Effect.Effect<PartID>
  }

  export type SessionRuntime = {
    runPromise: <A>(fn: (svc: SessionPartAPI) => Effect.Effect<A>) => Promise<A>
  }
}
