import { Effect, Cause, Stream } from "effect"
import * as Log from "@saeeol/core/util/log"
import * as EffectLogger from "@saeeol/core/effect/logger"
import * as Session from "../core/session"
import { MessageV2 } from "../message/message-v2"
import type { PromptDeps } from "./prompt-types"

const elog = EffectLogger.create({ service: "session.prompt" })

export const ensureTitle = (deps: PromptDeps) =>
  Effect.fn("SessionPrompt.ensureTitle")(function* (input: {
    session: Session.Info
    history: MessageV2.WithParts[]
    providerID: any
    modelID: any
  }) {
    if (input.session.parentID) return
    if (!Session.isDefaultTitle(input.session.title)) return
    const real = (m: MessageV2.WithParts) =>
      m.info.role === "user" && !m.parts.every((p) => "synthetic" in p && p.synthetic)
    const idx = input.history.findIndex(real)
    if (idx === -1) return
    if (input.history.filter(real).length !== 1) return
    const context = input.history.slice(0, idx + 1)
    const firstUser = context[idx]
    if (!firstUser || firstUser.info.role !== "user") return
    const firstInfo = firstUser.info
    const subtasks = firstUser.parts.filter((p): p is MessageV2.SubtaskPart => p.type === "subtask")
    const onlySubtasks = subtasks.length > 0 && firstUser.parts.every((p) => p.type === "subtask")
    const ag = yield* deps.agents.get("title")
    if (!ag) return
    const mdl = ag.model
      ? yield* deps.provider.getModel(ag.model.providerID, ag.model.modelID)
      : ((yield* deps.provider.getSmallModel(input.providerID)) ??
        (yield* deps.provider.getModel(input.providerID, input.modelID)))
    const msgs = onlySubtasks
      ? [{ role: "user" as const, content: subtasks.map((p) => p.prompt).join("\n") }]
      : yield* MessageV2.toModelMessagesEffect(context, mdl)
    const text = yield* deps.llm.stream({
      agent: ag, user: firstInfo, system: [], small: true, tools: {}, model: mdl,
      sessionID: input.session.id, retries: 2,
      messages: [{ role: "user", content: "Generate a title for this conversation:\n" }, ...msgs],
    }).pipe(
      Stream.filter((e: any): e is Extract<any, { type: "text-delta" }> => e.type === "text-delta"),
      Stream.map((e: any) => e.text),
      Stream.mkString,
      Effect.orDie,
    )
    const cleaned = text.replace(/<think[\s\S]*?<\/think>\s*/g, "")
      .split("\n").map((l: string) => l.trim()).find((l: string) => l.length > 0)
    if (!cleaned) return
    const t = cleaned.length > 100 ? cleaned.substring(0, 97) + "..." : cleaned
    yield* deps.sessions.setTitle({ sessionID: input.session.id, title: t })
      .pipe(Effect.catchCause((cause) => elog.error("failed to generate title", { error: Cause.squash(cause) })))
  })
