import { Hono, describeRoute, validator, resolver, z, Session, SessionCompaction, SessionRevert, SessionPrompt, Agent, SessionID, ProviderID, ModelID, Permission, PermissionID, errors, jsonRequest, log, zodObject } from "./_shared"

export const actionRoutes = new Hono()
  .post(
    "/:sessionID/summarize",
    describeRoute({
      summary: "Summarize session",
      description: "Generate a concise summary of the session using AI compaction to preserve key information.",
      operationId: "session.summarize",
      responses: {
        200: {
          description: "Summarized session",
          content: {
            "application/json": {
              schema: resolver(z.boolean()),
            },
          },
        },
        ...errors(400, 404),
      },
    }),
    validator(
      "param",
      z.object({
        sessionID: SessionID.zod,
      }),
    ),
    validator(
      "json",
      z.object({
        providerID: ProviderID.zod,
        modelID: ModelID.zod,
        auto: z.boolean().optional().default(false),
      }),
    ),
    async (c) =>
      jsonRequest("SessionRoutes.summarize", c, function* () {
        const sessionID = c.req.valid("param").sessionID
        const body = c.req.valid("json")
        const session = yield* Session.Service
        const revert = yield* SessionRevert.Service
        const compact = yield* SessionCompaction.Service
        const prompt = yield* SessionPrompt.Service
        const agent = yield* Agent.Service

        yield* revert.cleanup(yield* session.get(sessionID))
        const msgs = yield* session.messages({ sessionID })
        const defaultAgent = yield* agent.defaultAgent()
        let currentAgent = defaultAgent
        for (let i = msgs.length - 1; i >= 0; i--) {
          const info = msgs[i].info
          if (info.role === "user") {
            currentAgent = info.agent || defaultAgent
            break
          }
        }

        yield* compact.create({
          sessionID,
          agent: currentAgent,
          model: {
            providerID: body.providerID,
            modelID: body.modelID,
          },
          auto: body.auto,
        })
        yield* prompt.loop({ sessionID })
        return true
      }),
  )
  .post(
    "/:sessionID/revert",
    describeRoute({
      summary: "Revert message",
      description: "Revert a specific message in a session, undoing its effects and restoring the previous state.",
      operationId: "session.revert",
      responses: {
        200: {
          description: "Updated session",
          content: {
            "application/json": {
              schema: resolver(Session.Info.zod),
            },
          },
        },
        ...errors(400, 404),
      },
    }),
    validator(
      "param",
      z.object({
        sessionID: SessionID.zod,
      }),
    ),
    validator("json", zodObject(SessionRevert.RevertInput).omit({ sessionID: true })),
    async (c) => {
      const sessionID = c.req.valid("param").sessionID
      const body = c.req.valid("json") as Omit<SessionRevert.RevertInput, "sessionID">
      log.info("revert", body)
      return jsonRequest("SessionRoutes.revert", c, function* () {
        const svc = yield* SessionRevert.Service
        return yield* svc.revert({ sessionID, ...body })
      })
    },
  )
  .post(
    "/:sessionID/unrevert",
    describeRoute({
      summary: "Restore reverted messages",
      description: "Restore all previously reverted messages in a session.",
      operationId: "session.unrevert",
      responses: {
        200: {
          description: "Updated session",
          content: {
            "application/json": {
              schema: resolver(Session.Info.zod),
            },
          },
        },
        ...errors(400, 404),
      },
    }),
    validator(
      "param",
      z.object({
        sessionID: SessionID.zod,
      }),
    ),
    async (c) =>
      jsonRequest("SessionRoutes.unrevert", c, function* () {
        const sessionID = c.req.valid("param").sessionID
        const svc = yield* SessionRevert.Service
        return yield* svc.unrevert({ sessionID })
      }),
  )
  .post(
    "/:sessionID/permissions/:permissionID",
    describeRoute({
      summary: "Respond to permission",
      deprecated: true,
      description: "Approve or deny a permission request from the AI assistant.",
      operationId: "permission.respond",
      responses: {
        200: {
          description: "Permission processed successfully",
          content: {
            "application/json": {
              schema: resolver(z.boolean()),
            },
          },
        },
        ...errors(400, 404),
      },
    }),
    validator(
      "param",
      z.object({
        sessionID: SessionID.zod,
        permissionID: PermissionID.zod,
      }),
    ),
    validator("json", z.object({ response: Permission.Reply.zod })),
    async (c) =>
      jsonRequest("SessionRoutes.permissionRespond", c, function* () {
        const params = c.req.valid("param")
        const svc = yield* Permission.Service
        yield* svc.reply({
          requestID: params.permissionID,
          reply: c.req.valid("json").response,
        })
        return true
      }),
  )
  .post(
    "/viewed",
    describeRoute({
      summary: "Set viewed sessions",
      description: "Notify the server which sessions the user is currently viewing, or clear all.",
      operationId: "session.viewed",
      responses: {
        200: {
          description: "Viewed sessions updated",
          content: { "application/json": { schema: resolver(z.boolean()) } },
        },
      },
    }),
    validator(
      "json",
      z.object({
        focused: z.array(z.string()).optional(),
        open: z.array(z.string()).optional(),
      }),
    ),
    async (c) => {
      const { SaeeolSessions } = await import("@/sessions/sessions")
      const body = c.req.valid("json")
      SaeeolSessions.setViewedSessions({ focused: body.focused ?? [], open: body.open ?? [] })
      return c.json(true)
    },
  )
