import { data } from "react-router";

import { usersResource } from "~/server/headscale/live-store";
import { getOidcSubject } from "~/server/web/headscale-identity";
import { Capabilities } from "~/server/web/roles";
import type { Role } from "~/server/web/roles";

import type { Route } from "./+types/overview";

export async function userAction({ request, context }: Route.ActionArgs) {
  const principal = await context.auth.require(request);
  const check = await context.auth.can(principal, Capabilities.write_users);
  if (!check) {
    throw data("You do not have permission to update users", {
      status: 403,
    });
  }

  const formData = await request.formData();
  const action = formData.get("action_id")?.toString();
  if (!action) {
    throw data("Missing `action_id` in the form data.", {
      status: 404,
    });
  }

  const apiKey = context.auth.getHeadscaleApiKey(principal, context.oidc?.apiKey);
  const api = context.hsApi.getRuntimeClient(apiKey);
  switch (action) {
    case "create_user": {
      const name = formData.get("username")?.toString();
      const displayName = formData.get("display_name")?.toString();
      const email = formData.get("email")?.toString();

      if (!name) {
        throw data("Missing `username` in the form data.", {
          status: 400,
        });
      }

      await api.createUser(name, email, displayName);
      await context.hsLive.refresh(usersResource, api);
      return { message: "User created successfully" };
    }
    case "delete_user": {
      const userId = formData.get("user_id")?.toString();
      if (!userId) {
        throw data("Missing `user_id` in the form data.", {
          status: 400,
        });
      }

      await api.deleteUser(userId);
      await context.hsLive.refresh(usersResource, api);
      return { message: "User deleted successfully" };
    }
    case "rename_user": {
      const userId = formData.get("user_id")?.toString();
      const newName = formData.get("new_name")?.toString();
      if (!userId || !newName) {
        return data({ success: false }, 400);
      }

      const users = await api.getUsers(userId);
      const user = users.find((user) => user.id === userId);
      if (!user) {
        throw data(`No user found with id: ${userId}`, { status: 400 });
      }

      if (user.provider === "oidc") {
        // OIDC users cannot be renamed via this endpoint, return an error
        throw data("Users managed by OIDC cannot be renamed", {
          status: 403,
        });
      }

      await api.renameUser(userId, newName);
      await context.hsLive.refresh(usersResource, api);
      return { message: "User renamed successfully" };
    }
    case "reassign_user": {
      const userId = formData.get("user_id")?.toString();
      const newRole = formData.get("new_role")?.toString();
      if (!userId || !newRole) {
        throw data("Missing `user_id` or `new_role` in the form data.", {
          status: 400,
        });
      }

      const users = await api.getUsers(userId);
      const user = users.find((user) => user.id === userId);
      if (!user) {
        throw data("Specified user not found", {
          status: 400,
        });
      }

      const subject = getOidcSubject(user);
      if (!subject) {
        throw data("Specified user is not an OIDC user or has no subject.", { status: 400 });
      }

      const result = await context.auth.reassignSubject(subject, newRole as Role);

      if (!result) {
        throw data("Failed to reassign user role.", { status: 500 });
      }

      return { message: "User reassigned successfully" };
    }
    case "transfer_ownership": {
      if (principal.kind !== "oidc" || principal.user.role !== "owner") {
        throw data("Only the owner can transfer ownership.", { status: 403 });
      }

      const userId = formData.get("user_id")?.toString();
      if (!userId) {
        throw data("Missing `user_id` in the form data.", { status: 400 });
      }

      const users = await api.getUsers(userId);
      const user = users.find((user) => user.id === userId);
      if (!user) {
        throw data("Specified user not found", { status: 400 });
      }

      const targetSubject = getOidcSubject(user);
      if (!targetSubject) {
        throw data("Target user is not an OIDC user or has no subject.", { status: 400 });
      }

      const result = await context.auth.transferOwnership(principal.user.subject, targetSubject);
      if (!result) {
        throw data("Failed to transfer ownership.", { status: 500 });
      }

      return { message: "Ownership transferred successfully" };
    }
    case "link_user": {
      const userId = formData.get("user_id")?.toString();
      const headscaleUserId = formData.get("headscale_user_id")?.toString();
      if (!userId || !headscaleUserId) {
        throw data("Missing `user_id` or `headscale_user_id` in the form data.", {
          status: 400,
        });
      }

      const users = await api.getUsers(userId);
      const user = users.find((user) => user.id === userId);
      if (!user) {
        throw data("Specified user not found", { status: 400 });
      }

      const subject = getOidcSubject(user);
      if (!subject) {
        throw data("Specified user is not an OIDC user or has no subject.", { status: 400 });
      }

      const linked = await context.auth.linkHeadscaleUserBySubject(subject, headscaleUserId);
      if (!linked) {
        throw data("That Headscale user is already linked to another account.", { status: 409 });
      }

      return { message: "Headscale user linked successfully" };
    }
    default:
      throw data("Invalid `action_id` provided.", {
        status: 400,
      });
  }
}
