import { MessageV2 } from "@/session/message-v2"
import { Session } from "@/session/session"
import { Todo } from "@/session/todo"
import { MessageID, PartID, SessionID } from "@/session/schema"
import { Snapshot } from "@/snapshot"
import { Schema } from "effect"
import { HttpApi, HttpApiEndpoint, HttpApiError, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi"
import { Authorization } from "../middleware/authorization"
import { InstanceContextMiddleware } from "../middleware/instance-context"
import { WorkspaceRoutingMiddleware } from "../middleware/workspace-routing"
import { described } from "./metadata"
import {
  ListQuery, DiffQuery, MessagesQuery, StatusMap, UpdatePayload,
  ForkPayload, InitPayload, SummarizePayload, PromptPayload, CommandPayload,
  ShellPayload, RevertPayload, PermissionResponsePayload, SessionPaths,
} from "./session-schemas"
import { PermissionID } from "@/permission/schema"

export {
  ListQuery, DiffQuery, MessagesQuery, StatusMap, UpdatePayload,
  ForkPayload, InitPayload, SummarizePayload, PromptPayload, CommandPayload,
  ShellPayload, RevertPayload, PermissionResponsePayload, SessionPaths,
} from "./session-schemas"

export const SessionApi = HttpApi.make("session")
  .add(
    HttpApiGroup.make("session")
      .add(
        HttpApiEndpoint.get("list", SessionPaths.list, {
          query: ListQuery,
          success: described(Schema.Array(Session.Info), "List of sessions"),
        }).annotateMerge(OpenApi.annotations({ identifier: "session.list", summary: "List sessions", description: "Get a list of all Saeeol sessions, sorted by most recently updated." })),
        HttpApiEndpoint.get("status", SessionPaths.status, {
          success: described(StatusMap, "Get session status"),
          error: HttpApiError.BadRequest,
        }).annotateMerge(OpenApi.annotations({ identifier: "session.status", summary: "Get session status", description: "Retrieve the current status of all sessions." })),
        HttpApiEndpoint.get("get", SessionPaths.get, {
          params: { sessionID: SessionID },
          success: described(Session.Info, "Get session"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.get", summary: "Get session", description: "Retrieve detailed information about a specific session." })),
        HttpApiEndpoint.get("children", SessionPaths.children, {
          params: { sessionID: SessionID },
          success: described(Schema.Array(Session.Info), "List of children"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.children", summary: "Get session children", description: "Retrieve all child sessions forked from the specified parent." })),
        HttpApiEndpoint.get("todo", SessionPaths.todo, {
          params: { sessionID: SessionID },
          success: described(Schema.Array(Todo.Info), "Todo list"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.todo", summary: "Get session todos", description: "Retrieve the todo list associated with a session." })),
        HttpApiEndpoint.get("diff", SessionPaths.diff, {
          params: { sessionID: SessionID },
          query: DiffQuery,
          success: described(Schema.Array(Snapshot.FileDiff), "Successfully retrieved diff"),
        }).annotateMerge(OpenApi.annotations({ identifier: "session.diff", summary: "Get message diff", description: "Get file changes from a specific user message." })),
        HttpApiEndpoint.get("messages", SessionPaths.messages, {
          params: { sessionID: SessionID },
          query: MessagesQuery,
          success: described(Schema.Array(MessageV2.WithParts), "List of messages"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.messages", summary: "Get session messages", description: "Retrieve all messages in a session." })),
        HttpApiEndpoint.get("message", SessionPaths.message, {
          params: { sessionID: SessionID, messageID: MessageID },
          success: described(MessageV2.WithParts, "Message"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.message", summary: "Get message", description: "Retrieve a specific message by ID." })),
        HttpApiEndpoint.post("create", SessionPaths.create, {
          payload: [HttpApiSchema.NoContent, Session.CreateInput],
          success: described(Session.Info, "Successfully created session"),
          error: HttpApiError.BadRequest,
        }).annotateMerge(OpenApi.annotations({ identifier: "session.create", summary: "Create session", description: "Create a new session for interacting with AI assistants." })),
        HttpApiEndpoint.delete("remove", SessionPaths.remove, {
          params: { sessionID: SessionID },
          success: described(Schema.Boolean, "Successfully deleted session"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.delete", summary: "Delete session", description: "Delete a session and permanently remove all associated data." })),
        HttpApiEndpoint.patch("update", SessionPaths.update, {
          params: { sessionID: SessionID },
          payload: UpdatePayload,
          success: described(Session.Info, "Successfully updated session"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.update", summary: "Update session", description: "Update properties of an existing session." })),
        HttpApiEndpoint.post("fork", SessionPaths.fork, {
          params: { sessionID: SessionID },
          payload: ForkPayload,
          success: described(Session.Info, "200"),
        }).annotateMerge(OpenApi.annotations({ identifier: "session.fork", summary: "Fork session", description: "Create a new session by forking at a specific message." })),
        HttpApiEndpoint.post("abort", SessionPaths.abort, {
          params: { sessionID: SessionID },
          success: described(Schema.Boolean, "Aborted session"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.abort", summary: "Abort session", description: "Abort an active session and stop ongoing processing." })),
        HttpApiEndpoint.post("init", SessionPaths.init, {
          params: { sessionID: SessionID },
          payload: InitPayload,
          success: described(Schema.Boolean, "200"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.init", summary: "Initialize session", description: "Analyze the app and create an AGENTS.md file." })),
        HttpApiEndpoint.post("share", SessionPaths.share, {
          params: { sessionID: SessionID },
          success: described(Session.Info, "Successfully shared session"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.share", summary: "Share session", description: "Create a shareable link for a session." })),
        HttpApiEndpoint.delete("unshare", SessionPaths.share, {
          params: { sessionID: SessionID },
          success: described(Session.Info, "Successfully unshared session"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.unshare", summary: "Unshare session", description: "Remove the shareable link for a session." })),
        HttpApiEndpoint.post("summarize", SessionPaths.summarize, {
          params: { sessionID: SessionID },
          payload: SummarizePayload,
          success: described(Schema.Boolean, "Summarized session"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.summarize", summary: "Summarize session", description: "Generate a summary using AI compaction." })),
        HttpApiEndpoint.post("prompt", SessionPaths.prompt, {
          params: { sessionID: SessionID },
          payload: PromptPayload,
          success: described(MessageV2.WithParts, "Created message"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.prompt", summary: "Send message", description: "Send a message to a session, streaming the AI response." })),
        HttpApiEndpoint.post("promptAsync", SessionPaths.promptAsync, {
          params: { sessionID: SessionID },
          payload: PromptPayload,
          success: described(HttpApiSchema.NoContent, "Prompt accepted"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.prompt_async", summary: "Send async message", description: "Send a message asynchronously, returning immediately." })),
        HttpApiEndpoint.post("command", SessionPaths.command, {
          params: { sessionID: SessionID },
          payload: CommandPayload,
          success: described(MessageV2.WithParts, "Created message"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.command", summary: "Send command", description: "Send a command for execution by the AI assistant." })),
        HttpApiEndpoint.post("shell", SessionPaths.shell, {
          params: { sessionID: SessionID },
          payload: ShellPayload,
          success: described(MessageV2.WithParts, "Created message"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.shell", summary: "Run shell command", description: "Execute a shell command within the session context." })),
        HttpApiEndpoint.post("revert", SessionPaths.revert, {
          params: { sessionID: SessionID },
          payload: RevertPayload,
          success: described(Session.Info, "Updated session"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.revert", summary: "Revert message", description: "Revert a message, undoing its effects." })),
        HttpApiEndpoint.post("unrevert", SessionPaths.unrevert, {
          params: { sessionID: SessionID },
          success: described(Session.Info, "Updated session"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.unrevert", summary: "Restore reverted messages", description: "Restore all previously reverted messages." })),
        HttpApiEndpoint.post("permissionRespond", SessionPaths.permissions, {
          params: { sessionID: SessionID, permissionID: PermissionID },
          payload: PermissionResponsePayload,
          success: described(Schema.Boolean, "Permission processed successfully"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "permission.respond", summary: "Respond to permission", description: "Approve or deny a permission request.", deprecated: true })),
        HttpApiEndpoint.delete("deleteMessage", SessionPaths.deleteMessage, {
          params: { sessionID: SessionID, messageID: MessageID },
          success: described(Schema.Boolean, "Successfully deleted message"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "session.deleteMessage", summary: "Delete message", description: "Delete a message without reverting file changes." })),
        HttpApiEndpoint.delete("deletePart", SessionPaths.deletePart, {
          params: { sessionID: SessionID, messageID: MessageID, partID: PartID },
          success: described(Schema.Boolean, "Successfully deleted part"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "part.delete", description: "Delete a part from a message." })),
        HttpApiEndpoint.patch("updatePart", SessionPaths.updatePart, {
          params: { sessionID: SessionID, messageID: MessageID, partID: PartID },
          payload: MessageV2.Part,
          success: described(MessageV2.Part, "Successfully updated part"),
          error: [HttpApiError.BadRequest, HttpApiError.NotFound],
        }).annotateMerge(OpenApi.annotations({ identifier: "part.update", description: "Update a part in a message." })),
      )
      .annotateMerge(OpenApi.annotations({ title: "session", description: "Experimental HttpApi session routes." }))
      .middleware(InstanceContextMiddleware)
      .middleware(WorkspaceRoutingMiddleware)
      .middleware(Authorization),
  )
  .annotateMerge(OpenApi.annotations({ title: "saeeol experimental HttpApi", version: "0.0.1", description: "Experimental HttpApi surface for selected instance routes." }))
