import z from "zod"
import { remapChildren as _remapChildren } from "./fork"
import { Schema } from "effect"
import { Session } from "@/session/session"
import { SessionID, MessageID } from "@/session/schema"
import { makeRuntime } from "@/effect/run-service"
import { fn } from "@/util/fn"
import * as Platform from "./platform"
import * as Queries from "./queries"
import type { ProjectInfo as ProjectInfoType } from "./queries"

export namespace SaeeolSession {
  export type CloseReason = Schema.Schema.Type<typeof Platform.CloseReasonSchema>

  export const Event = Platform.Event

  export const register = Platform.register
  export const setPlatformOverride = Platform.setPlatformOverride
  export const getPlatformOverride = Platform.getPlatformOverride
  export const resolvePlatform = Platform.resolvePlatform
  export const resolveRoot = Platform.resolveRoot
  export const featureForPlatform = Platform.featureForPlatform
  export const clearPlatformOverride = Platform.clearPlatformOverride
  export const attribution = Platform.attribution

  export const family = Queries.family
  export const filters = Queries.filters
  export const providerCost = Queries.providerCost
  export const runSyncSafe = Queries.runSyncSafe

  export const ProjectInfo = Queries.ProjectInfo
  export type ProjectInfo = ProjectInfoType

  export const listGlobal = Queries.listGlobal

  export async function shareSession(id: string): Promise<{ url: string }> {
    const { SaeeolSessions } = await import("@/sessions/sessions")
    return SaeeolSessions.share(id)
  }

  export async function unshareSession(id: string): Promise<void> {
    const { SaeeolSessions } = await import("@/sessions/sessions")
    await SaeeolSessions.unshare(id)
  }

  export async function removeSession(id: string): Promise<void> {
    const { SaeeolSessions } = await import("@/sessions/sessions")
    await SaeeolSessions.remove(id).catch(() => {})
  }

  export async function cleanup(id: string): Promise<void> {
    await removeSession(id)
    Platform.clearPlatformOverride(id)
    const [app, state] = await Promise.all([import("@/effect/app-runtime"), import("@/session/run-state")])
    const { SessionID: SID } = await import("@/session/schema")
    await app.AppRuntime.runPromise(state.SessionRunState.Service.use((svc) => svc.cancel(SID.make(id))))
  }

  export const remapChildren = _remapChildren
}

export const saeeolSessionFork = fn(
  z.object({ sessionID: SessionID.zod, messageID: MessageID.zod.optional() }),
  async (input) => {
    const { runPromise } = makeRuntime(Session.Service, Session.defaultLayer)
    const session = await runPromise((svc) => svc.fork(input))
    await SaeeolSession.remapChildren(session.id)
    return session
  },
)
