import type { FastifyPluginAsyncZod } from "@fastify/type-provider-zod"
import {
  appUserCreateSchema,
  appUserIdParamSchema,
  appUserUpdateSchema,
  bindingIdParamSchema,
  interfaceCatalogQuerySchema,
  userBindingCreateSchema,
  type AppUserCreate,
  type AppUserUpdate,
  type UserBindingCreate,
} from "@mmapp/contracts/users"
import {
  addBinding,
  createUser,
  deleteUser,
  getUserById,
  listInterfaceCatalog,
  listUsers,
  removeBinding,
  updateUser,
  UsersServiceError,
} from "../modules/users/service/users-service.js"

function sendServiceError(reply: { status: (c: number) => { send: (b: unknown) => unknown } }, err: unknown) {
  if (err instanceof UsersServiceError) {
    return reply.status(err.status).send({ error: err.message })
  }
  throw err
}

const usersRoutes: FastifyPluginAsyncZod = async (app) => {
  app.get("/users", async (_req, reply) => {
    return reply.send({ users: listUsers() })
  })

  app.get("/users/interface-catalog", {
    schema: { querystring: interfaceCatalogQuerySchema },
  }, async (req, reply) => {
    const q = req.query as { serverId: number }
    try {
      return reply.send({ interfaces: await listInterfaceCatalog(q.serverId) })
    } catch (err) {
      return sendServiceError(reply, err)
    }
  })

  app.get("/users/:id", {
    schema: { params: appUserIdParamSchema },
  }, async (req, reply) => {
    const { id } = req.params as { id: string }
    const user = getUserById(id)
    if (!user) return reply.status(404).send({ error: "Пользователь не найден" })
    return reply.send({ user })
  })

  app.post("/users", {
    schema: { body: appUserCreateSchema },
  }, async (req, reply) => {
    try {
      const user = createUser(req.body as AppUserCreate)
      return reply.status(201).send({ user })
    } catch (err) {
      return sendServiceError(reply, err)
    }
  })

  app.patch("/users/:id", {
    schema: { params: appUserIdParamSchema, body: appUserUpdateSchema },
  }, async (req, reply) => {
    const { id } = req.params as { id: string }
    try {
      const user = updateUser(id, req.body as AppUserUpdate)
      return reply.send({ user })
    } catch (err) {
      return sendServiceError(reply, err)
    }
  })

  app.delete("/users/:id", {
    schema: { params: appUserIdParamSchema },
  }, async (req, reply) => {
    const { id } = req.params as { id: string }
    try {
      deleteUser(id)
      return reply.status(204).send()
    } catch (err) {
      return sendServiceError(reply, err)
    }
  })

  app.post("/users/:id/bindings", {
    schema: { params: appUserIdParamSchema, body: userBindingCreateSchema },
  }, async (req, reply) => {
    const { id } = req.params as { id: string }
    try {
      const binding = addBinding(id, req.body as UserBindingCreate)
      return reply.status(201).send({ binding })
    } catch (err) {
      return sendServiceError(reply, err)
    }
  })

  app.delete("/users/:id/bindings/:bindingId", {
    schema: { params: bindingIdParamSchema },
  }, async (req, reply) => {
    const { id, bindingId } = req.params as { id: string; bindingId: string }
    try {
      removeBinding(id, bindingId)
      return reply.status(204).send()
    } catch (err) {
      return sendServiceError(reply, err)
    }
  })
}

export default usersRoutes
