import { FastifyInstance } from "fastify";
import prisma from "../../config/database";
import { requirePermission } from "../../middleware/auth";
import { logAudit } from "../../services/audit";
import { success, error, parseId, paginated } from "../../utils/response";
import { parsePagination, buildPaginationMeta } from "../../utils/pagination";
import { parseBody } from "../../schemas/common";
import { CreateUserSchema, UpdateUserSchema } from "../../schemas/users.schema";
import {
  listUsers,
  getUser,
  createUser,
  updateUser,
  deleteUser,
} from "../../services/users.service";

export default async function usersRoutes(
  fastify: FastifyInstance,
): Promise<void> {
  // GET /api/admin/users
  fastify.get(
    "/",
    { preHandler: requirePermission("users.view") },
    async (request, reply) => {
      const query = request.query as Record<string, unknown>;
      const params = parsePagination(query);
      const permission = query.permission
        ? String(query.permission)
        : undefined;
      const result = await listUsers({ ...params, permission });

      return paginated(
        reply,
        result.users,
        buildPaginationMeta(result.total, result.page, result.limit),
      );
    },
  );

  // GET /api/admin/users/:id
  fastify.get<{ Params: { id: string } }>(
    "/:id",
    { preHandler: requirePermission("users.view") },
    async (request, reply) => {
      const id = parseId(request.params.id, reply);
      if (id === null) return;

      const user = await getUser(id);
      if (!user) return error(reply, "Uživatel nenalezen", 404);
      return success(reply, user);
    },
  );

  // POST /api/admin/users
  fastify.post(
    "/",
    { preHandler: requirePermission("users.create") },
    async (request, reply) => {
      const parsed = parseBody(CreateUserSchema, request.body);
      if ("error" in parsed) return error(reply, parsed.error, 400);
      const body = parsed.data;

      const result = await createUser(
        {
          username: body.username,
          email: body.email,
          password: body.password,
          first_name: body.first_name,
          last_name: body.last_name,
          role_id: body.role_id,
          is_active: body.is_active,
        },
        request.authData?.roleName ?? undefined,
      );

      if ("error" in result) return error(reply, result.error!, result.status!);

      await logAudit({
        request,
        authData: request.authData,
        action: "create",
        entityType: "user",
        entityId: result.user.id,
        description: `Vytvořen uživatel ${result.user.username}`,
      });

      return success(
        reply,
        { id: result.user.id },
        201,
        "Uživatel byl vytvořen",
      );
    },
  );

  // PUT /api/admin/users/:id
  fastify.put<{ Params: { id: string } }>(
    "/:id",
    { preHandler: requirePermission("users.edit") },
    async (request, reply) => {
      const id = parseId(request.params.id, reply);
      if (id === null) return;
      const parsed = parseBody(UpdateUserSchema, request.body);
      if ("error" in parsed) return error(reply, parsed.error, 400);

      // Privilege-escalation guard: role changes and activation toggles are
      // admin-only. Any other `users.edit` holder (e.g. "manager") could
      // otherwise reassign roles or disable other accounts.
      const callerIsAdmin = request.authData?.roleName === "admin";
      const userData: Record<string, unknown> = { ...parsed.data };
      if (!callerIsAdmin) {
        delete userData.role_id;
        delete userData.is_active;
      }
      if (userData.role_id != null) {
        userData.role_id = Number(userData.role_id);
      }

      const result = await updateUser(
        id,
        userData as Parameters<typeof updateUser>[1],
        request.authData?.roleName ?? undefined,
      );
      if ("error" in result) return error(reply, result.error!, result.status!);

      if (parsed.data.password) {
        await prisma.refresh_tokens.updateMany({
          where: { user_id: id, replaced_at: null },
          data: { replaced_at: new Date() },
        });
      }

      await logAudit({
        request,
        authData: request.authData,
        action: "update",
        entityType: "user",
        entityId: id,
        description: `Upraven uživatel ${result.username}`,
      });

      return success(reply, { id }, 200, "Uživatel byl uložen");
    },
  );

  // DELETE /api/admin/users/:id
  fastify.delete<{ Params: { id: string } }>(
    "/:id",
    { preHandler: requirePermission("users.delete") },
    async (request, reply) => {
      const id = parseId(request.params.id, reply);
      if (id === null) return;

      const result = await deleteUser(id, request.authData?.userId);
      if ("error" in result) return error(reply, result.error!, result.status!);

      await logAudit({
        request,
        authData: request.authData,
        action: "delete",
        entityType: "user",
        entityId: id,
        description: `Smazán uživatel ${result.username}`,
      });

      return success(reply, null, 200, "Uživatel smazán");
    },
  );
}
