import { Hono, describeRoute, validator, resolver, z, Session, SessionPrompt, SessionShare, SessionSummary, Snapshot, Command, SessionID, ModelID, ProviderID, MessageID, errors, jsonRequest, zodObject } from "./_shared"

export const shareRoutes = new Hono()
  .post(
    "/:sessionID/init",
    describeRoute({
      summary: "Initialize session",
      description:
        "Analyze the current application and create an AGENTS.md file with project-specific agent configurations.",
      operationId: "session.init",
      responses: {
        200: {
          description: "200",
          content: {
            "application/json": {
              schema: resolver(z.boolean()),
            },
          },
        },
        ...errors(400, 404),
      },
    }),
    validator(
      "param",
      z.object({
        sessionID: SessionID.zod,
      }),
    ),
    validator(
      "json",
      z.object({
        modelID: ModelID.zod,
        providerID: ProviderID.zod,
        messageID: MessageID.zod,
      }),
    ),
    async (c) =>
      jsonRequest("SessionRoutes.init", c, function* () {
        const sessionID = c.req.valid("param").sessionID
        const body = c.req.valid("json")
        const svc = yield* SessionPrompt.Service
        yield* svc.command({
          sessionID,
          messageID: body.messageID,
          model: body.providerID + "/" + body.modelID,
          command: Command.Default.INIT,
          arguments: "",
        })
        return true
      }),
  )
  .post(
    "/:sessionID/fork",
    describeRoute({
      summary: "Fork session",
      description: "Create a new session by forking an existing session at a specific message point.",
      operationId: "session.fork",
      responses: {
        200: {
          description: "200",
          content: {
            "application/json": {
              schema: resolver(Session.Info.zod),
            },
          },
        },
        ...errors(400, 404),
      },
    }),
    validator(
      "param",
      z.object({
        sessionID: SessionID.zod,
      }),
    ),
    validator("json", zodObject(Session.ForkInput).omit({ sessionID: true })),
    async (c) =>
      jsonRequest("SessionRoutes.fork", c, function* () {
        const sessionID = c.req.valid("param").sessionID
        const body = c.req.valid("json") as { messageID?: MessageID }
        const svc = yield* Session.Service
        return yield* svc.fork({ ...body, sessionID })
      }),
  )
  .post(
    "/:sessionID/abort",
    describeRoute({
      summary: "Abort session",
      description: "Abort an active session and stop any ongoing AI processing or command execution.",
      operationId: "session.abort",
      responses: {
        200: {
          description: "Aborted session",
          content: {
            "application/json": {
              schema: resolver(z.boolean()),
            },
          },
        },
        ...errors(400, 404),
      },
    }),
    validator(
      "param",
      z.object({
        sessionID: SessionID.zod,
      }),
    ),
    async (c) =>
      jsonRequest("SessionRoutes.abort", c, function* () {
        const svc = yield* SessionPrompt.Service
        yield* svc.cancel(c.req.valid("param").sessionID)
        return true
      }),
  )
  .post(
    "/:sessionID/share",
    describeRoute({
      summary: "Share session",
      description: "Create a shareable link for a session, allowing others to view the conversation.",
      operationId: "session.share",
      responses: {
        200: {
          description: "Successfully shared session",
          content: {
            "application/json": {
              schema: resolver(Session.Info.zod),
            },
          },
        },
        ...errors(400, 404),
      },
    }),
    validator(
      "param",
      z.object({
        sessionID: SessionID.zod,
      }),
    ),
    async (c) =>
      jsonRequest("SessionRoutes.share", c, function* () {
        const sessionID = c.req.valid("param").sessionID
        const share = yield* SessionShare.Service
        const session = yield* Session.Service
        yield* share.share(sessionID)
        return yield* session.get(sessionID)
      }),
  )
  .delete(
    "/:sessionID/share",
    describeRoute({
      summary: "Unshare session",
      description: "Remove the shareable link for a session, making it private again.",
      operationId: "session.unshare",
      responses: {
        200: {
          description: "Successfully unshared session",
          content: {
            "application/json": {
              schema: resolver(Session.Info.zod),
            },
          },
        },
        ...errors(400, 404),
      },
    }),
    validator(
      "param",
      z.object({
        sessionID: SessionID.zod,
      }),
    ),
    async (c) =>
      jsonRequest("SessionRoutes.unshare", c, function* () {
        const sessionID = c.req.valid("param").sessionID
        const share = yield* SessionShare.Service
        const session = yield* Session.Service
        yield* share.unshare(sessionID)
        return yield* session.get(sessionID)
      }),
  )
  .get(
    "/:sessionID/diff",
    describeRoute({
      summary: "Get message diff",
      description: "Get the file changes (diff) that resulted from a specific user message in the session.",
      operationId: "session.diff",
      responses: {
        200: {
          description: "Successfully retrieved diff",
          content: {
            "application/json": {
              schema: resolver(Snapshot.FileDiff.zod.array()),
            },
          },
        },
      },
    }),
    validator(
      "param",
      z.object({
        sessionID: SessionID.zod,
      }),
    ),
    validator("query", zodObject(SessionSummary.DiffInput).omit({ sessionID: true })),
    async (c) =>
      jsonRequest("SessionRoutes.diff", c, function* () {
        const query = c.req.valid("query") as Omit<SessionSummary.DiffInput, "sessionID">
        const params = c.req.valid("param")
        const summary = yield* SessionSummary.Service
        return yield* summary.diff({
          sessionID: params.sessionID,
          messageID: query.messageID,
        })
      }),
  )
