import { Layer } from "effect"
import { Agent } from "@/agent/agent"
import { Provider } from "@/provider/provider"
import { ProviderID, ModelID } from "@/provider/schema"
import { Question } from "@/question"
import { Todo } from "@/session/todo"
import { makeRuntime } from "@/effect/run-service"
import { SessionID } from "@/session/schema"
import { Session } from "@/session/session"
import * as Log from "@saeeol/core/util/log"
import { defaultLayer as subtaskLayer } from "@/session/subtask"
import { defaultLayer as shellLayer } from "@/session/shell-exec"
import { MessageV2 } from "@/session/message-v2"

const agents = makeRuntime(Agent.Service, Agent.defaultLayer)
const providers = makeRuntime(Provider.Service, Provider.defaultLayer)
const questions = makeRuntime(Question.Service, Question.defaultLayer)
const todo = makeRuntime(Todo.Service, Todo.defaultLayer)

export const pending = new Map<SessionID, AbortController>()

export function toText(item: MessageV2.WithParts): string {
  return item.parts
    .filter((part): part is MessageV2.TextPart => part.type === "text")
    .map((part) => part.text)
    .join("\n")
    .trim()
}

export const HANDOVER_PROMPT = `You are summarizing a planning session to hand off to an implementation session.

The plan itself will be provided separately — do NOT repeat it. Instead, focus on information discovered during planning that would help the implementing agent but is NOT already in the plan text.

Produce a concise summary using this template:
---
## Discoveries

[Key findings from code exploration — architecture patterns, gotchas, edge cases, relevant existing code that the plan references but doesn't fully explain]

## Relevant Files

[Structured list of files/directories that were read or discussed, with brief notes on what's relevant in each]

## Implementation Notes

[Any important context: conventions to follow, potential pitfalls, dependencies between steps, things the implementing agent should watch out for]
---

If there is nothing useful to add beyond what the plan already says, respond with an empty string.
Keep the summary concise — focus on high-entropy information that would save the implementing agent time.`

export const PlanFollowupRuntime = {
  agent(name: string): Promise<Agent.Info | undefined> {
    return agents.runPromise((svc) => svc.get(name))
  },
  model(providerID: ProviderID, modelID: ModelID): Promise<Provider.Model> {
    return providers.runPromise((svc) => svc.getModel(providerID, modelID))
  },
  question: {
    ask(input: Parameters<Question.Interface["ask"]>[0]) {
      return questions.runPromise((svc) => svc.ask(input))
    },
    list() {
      return questions.runPromise((svc) => svc.list())
    },
    reject(requestID: Parameters<Question.Interface["reject"]>[0]) {
      return questions.runPromise((svc) => svc.reject(requestID))
    },
  },
  todo: {
    get(sessionID: SessionID) {
      return todo.runPromise((svc) => svc.get(sessionID))
    },
    update(input: Parameters<Todo.Interface["update"]>[0]) {
      return todo.runPromise((svc) => svc.update(input))
    },
  },
  async loop(sessionID: SessionID) {
    const item = await import("@/session/prompt")
    const prompt = makeRuntime(item.SessionPrompt.Service, item.SessionPrompt.defaultLayer.pipe(
      Layer.provide(subtaskLayer),
      Layer.provide(shellLayer),
    ))
    return prompt.runPromise((svc) => svc.loop({ sessionID }))
  },
}
