// The Lucia project.
// Copyright 2026-2026 DSP, inc.  All rights reserved.
// Authors:
//   imacat.yang@dsp.im (imacat), 2026/03/05

import { describe, it, expect, beforeEach, vi } from "vitest";
import { setActivePinia, createPinia } from "pinia";
import { http, HttpResponse } from "msw";
import { server } from "@/mocks/node.js";
import { findRequest, captureRequest } from "@/mocks/request-log.js";

vi.mock("@/module/apiError.js", () => ({
  default: vi.fn(),
}));

// Mock login store to avoid its side effects
vi.mock("@/stores/login", async () => {
  const { defineStore } = await import("pinia");
  return {
    useLoginStore: defineStore("loginStore", {
      state: () => ({
        userData: { username: "currentUser", name: "Current" },
      }),
      actions: {
        getUserData: vi.fn(),
      },
    }),
  };
});

import { useAcctMgmtStore } from "@/stores/acctMgmt";

describe("acctMgmtStore", () => {
  let store;

  beforeEach(() => {
    setActivePinia(createPinia());
    store = useAcctMgmtStore();
    document.cookie = "luciaToken=fake-test-token";
  });

  it("has correct default state", () => {
    expect(store.allUserAccountList).toEqual([]);
    expect(store.isAcctMenuOpen).toBe(false);
  });

  describe("menu actions", () => {
    it("openAcctMenu sets true", () => {
      store.openAcctMenu();
      expect(store.isAcctMenuOpen).toBe(true);
    });

    it("closeAcctMenu sets false", () => {
      store.openAcctMenu();
      store.closeAcctMenu();
      expect(store.isAcctMenuOpen).toBe(false);
    });

    it("toggleIsAcctMenuOpen toggles", () => {
      store.toggleIsAcctMenuOpen();
      expect(store.isAcctMenuOpen).toBe(true);
      store.toggleIsAcctMenuOpen();
      expect(store.isAcctMenuOpen).toBe(false);
    });
  });

  describe("setCurrentViewingUser", () => {
    it("finds user by username", () => {
      store.allUserAccountList = [
        { username: "alice", name: "Alice", detail: {} },
        { username: "bob", name: "Bob", detail: {} },
      ];
      store.setCurrentViewingUser("bob");
      expect(store.currentViewingUser.name).toBe("Bob");
    });
  });

  describe("clearCurrentViewingUser", () => {
    it("resets to empty user", () => {
      store.currentViewingUser = { username: "test", detail: {} };
      store.clearCurrentViewingUser();
      expect(store.currentViewingUser.username).toBe("");
    });
  });

  describe("createNewAccount", () => {
    it("posts to /api/users and sets flag on success", async () => {
      const randomPassword = crypto.randomUUID();
      const user = { username: "newuser", password: randomPassword };
      server.use(
        http.post("/api/users", async ({ request }) => {
          const body = await request.json();
          captureRequest("POST", new URL(request.url).pathname, body);
          return new HttpResponse(null, { status: 200 });
        }),
      );

      await store.createNewAccount(user);

      const reqs = findRequest("POST", "/api/users");
      expect(reqs).toHaveLength(1);
      expect(reqs[0].body).toEqual(user);
      expect(store.isOneAccountJustCreate).toBe(true);
      expect(store.justCreateUsername).toBe("newuser");
    });
  });

  describe("deleteAccount", () => {
    it("returns true on success", async () => {
      server.use(
        http.delete("/api/users/:username", ({ request }) => {
          captureRequest("DELETE", new URL(request.url).pathname);
          return new HttpResponse(null, { status: 200 });
        }),
      );

      const result = await store.deleteAccount("alice");

      const reqs = findRequest("DELETE", "/api/users/alice");
      expect(reqs).toHaveLength(1);
      expect(result).toBe(true);
    });

    it("encodes special characters in username", async () => {
      server.use(
        http.delete("/api/users/:username", ({ request }) => {
          captureRequest("DELETE", new URL(request.url).pathname);
          return new HttpResponse(null, { status: 200 });
        }),
      );

      await store.deleteAccount("user@domain/name");

      const reqs = findRequest("DELETE",
        "/api/users/user%40domain%2Fname");
      expect(reqs).toHaveLength(1);
    });

    it("returns false on error", async () => {
      server.use(
        http.delete("/api/users/:username", () =>
          new HttpResponse(null, { status: 500 }),
        ),
      );

      const result = await store.deleteAccount("alice");

      expect(result).toBe(false);
    });
  });

  describe("editAccount", () => {
    it("puts edited data", async () => {
      const randomPassword = crypto.randomUUID();
      const detail = {
        username: "alice",
        password: randomPassword,
        name: "Alice",
        is_active: true,
      };
      server.use(
        http.put("/api/users/:username", async ({ request }) => {
          const body = await request.json();
          captureRequest("PUT", new URL(request.url).pathname, body);
          return new HttpResponse(null, { status: 200 });
        }),
      );

      const result = await store.editAccount("alice", detail);

      const reqs = findRequest("PUT", "/api/users/alice");
      expect(reqs).toHaveLength(1);
      expect(reqs[0].body.password).toBe(randomPassword);
      expect(result).toBe(true);
    });
  });

  describe("addRoleToUser", () => {
    it("puts role assignment", async () => {
      server.use(
        http.put("/api/users/:username/roles/:role", ({ request }) => {
          captureRequest("PUT", new URL(request.url).pathname);
          return new HttpResponse(null, { status: 200 });
        }),
      );

      const result = await store.addRoleToUser("alice", "admin");

      const reqs = findRequest("PUT", "/api/users/alice/roles/admin");
      expect(reqs).toHaveLength(1);
      expect(result).toBe(true);
    });

    it("encodes special characters in username and role", async () => {
      server.use(
        http.put("/api/users/:username/roles/:role", ({ request }) => {
          captureRequest("PUT", new URL(request.url).pathname);
          return new HttpResponse(null, { status: 200 });
        }),
      );

      await store.addRoleToUser("user@org", "role/special");

      const reqs = findRequest("PUT",
        "/api/users/user%40org/roles/role%2Fspecial");
      expect(reqs).toHaveLength(1);
    });
  });

  describe("deleteRoleToUser", () => {
    it("deletes role", async () => {
      server.use(
        http.delete("/api/users/:username/roles/:role", ({ request }) => {
          captureRequest("DELETE", new URL(request.url).pathname);
          return new HttpResponse(null, { status: 200 });
        }),
      );

      const result = await store.deleteRoleToUser("alice", "admin");

      const reqs = findRequest("DELETE",
        "/api/users/alice/roles/admin");
      expect(reqs).toHaveLength(1);
      expect(result).toBe(true);
    });
  });

  describe("getUserDetail", () => {
    it("fetches user and sets admin flag", async () => {
      server.use(
        http.get("/api/users/:username", () =>
          HttpResponse.json({
            username: "alice",
            roles: [{ code: "admin" }],
          }),
        ),
      );

      const result = await store.getUserDetail("alice");

      expect(result).toBe(true);
      expect(store.currentViewingUser.is_admin).toBe(true);
    });

    it("returns false on error", async () => {
      server.use(
        http.get("/api/users/:username", () =>
          new HttpResponse(null, { status: 500 }),
        ),
      );

      const result = await store.getUserDetail("ghost");

      expect(result).toBe(false);
    });
  });

  describe("hover state actions", () => {
    beforeEach(() => {
      store.allUserAccountList = [
        {
          username: "alice",
          isDeleteHovered: false,
          isRowHovered: false,
          isEditHovered: false,
          isDetailHovered: false,
        },
      ];
    });

    it("changeIsDeleteHoveredByUser", () => {
      store.changeIsDeleteHoveredByUser("alice", true);
      expect(store.allUserAccountList[0].isDeleteHovered).toBe(true);
    });

    it("changeIsRowHoveredByUser", () => {
      store.changeIsRowHoveredByUser("alice", true);
      expect(store.allUserAccountList[0].isRowHovered).toBe(true);
    });

    it("changeIsEditHoveredByUser", () => {
      store.changeIsEditHoveredByUser("alice", true);
      expect(store.allUserAccountList[0].isEditHovered).toBe(true);
    });

    it("changeIsDetailHoveredByUser", () => {
      store.changeIsDetailHoveredByUser("alice", true);
      expect(store.allUserAccountList[0].isDetailHovered).toBe(true);
    });
  });

  describe("moveCurrentLoginUserToFirstRow", () => {
    it("moves logged-in user to first position", async () => {
      const list = [
        { username: "alice", name: "Alice" },
        { username: "currentUser", name: "Current" },
        { username: "bob", name: "Bob" },
      ];
      const result = await store.moveCurrentLoginUserToFirstRow(list);
      expect(result.map((u) => u.username)).toEqual([
        "currentUser",
        "alice",
        "bob",
      ]);
    });

    it("preserves list when logged-in user is not found", async () => {
      const list = [
        { username: "alice", name: "Alice" },
        { username: "bob", name: "Bob" },
        { username: "charlie", name: "Charlie" },
      ];
      const result = await store.moveCurrentLoginUserToFirstRow(list);
      expect(result.map((u) => u.username)).toEqual([
        "alice",
        "bob",
        "charlie",
      ]);
    });
  });

  it("resetJustCreateFlag resets flag", () => {
    store.isOneAccountJustCreate = true;
    store.resetJustCreateFlag();
    expect(store.isOneAccountJustCreate).toBe(false);
  });

  it("setShouldUpdateList sets boolean", () => {
    store.setShouldUpdateList(true);
    expect(store.shouldUpdateList).toBe(true);
  });

  it("updateSingleAccountPiniaState updates user", () => {
    store.allUserAccountList = [{ username: "alice", name: "Old" }];
    store.updateSingleAccountPiniaState({
      username: "alice",
      name: "New",
    });
    expect(store.allUserAccountList[0].name).toBe("New");
  });
});
