package com.xly.erp.module.usr.controller;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xly.erp.common.security.TestJwtHelper;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ActiveProfiles;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
class UserControllerIT {

    @Autowired
    private TestRestTemplate rest;

    @Autowired
    private TestJwtHelper testJwtHelper;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @LocalServerPort
    private int port;

    @BeforeEach
    @AfterEach
    void cleanup() {
        jdbcTemplate.update("DELETE FROM tUserPermission WHERE iUserId IN "
                + "(SELECT iIncrement FROM tUser WHERE sUserNo LIKE 'sp_test_%')");
        jdbcTemplate.update("DELETE FROM tUser WHERE sUserNo LIKE 'sp_test_%'");
        jdbcTemplate.update("DELETE FROM tStaff WHERE sStaffNo LIKE 'sp_test_%'");
        jdbcTemplate.update("DELETE FROM tPermissionCategory WHERE sCategoryCode LIKE 'sp_test_%'");
    }

    @Test
    void postValidBody_with_jwt_returns200_andPersists() throws Exception {
        Integer staffId = insertStaff("sp_test_st1", "员工1");
        Integer cat1 = insertCategory("sp_test_pc1", "权限A");
        Integer cat2 = insertCategory("sp_test_pc2", "权限B");

        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);
        Map<String, Object> body = baseBody("sp_test_u_ok", "正常用户");
        body.put("iStaffId", staffId);
        body.put("permissionCategoryIds", List.of(cat1, cat2));

        ResponseEntity<String> resp = rest.exchange(
                url(), HttpMethod.POST, new HttpEntity<>(body, headers), String.class);

        JsonNode jb = objectMapper.readTree(resp.getBody());
        assertThat(jb.get("code").asInt()).isZero();
        int newId = jb.get("data").get("iIncrement").asInt();
        assertThat(jb.get("data").get("sUserNo").asText()).isEqualTo("sp_test_u_ok");

        Map<String, Object> row = jdbcTemplate.queryForMap(
                "SELECT sBrandsId, sCreatedBy, sUserType FROM tUser WHERE iIncrement = ?", newId);
        assertThat(row.get("sBrandsId")).isEqualTo("XLY");
        assertThat(row.get("sCreatedBy")).isEqualTo("ADMIN001");
        Integer permCount = jdbcTemplate.queryForObject(
                "SELECT COUNT(1) FROM tUserPermission WHERE iUserId = ?", Integer.class, newId);
        assertThat(permCount).isEqualTo(2);
    }

    @Test
    void postEmptyBody_returns40001() throws Exception {
        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);

        ResponseEntity<String> resp = rest.exchange(
                url(), HttpMethod.POST, new HttpEntity<>("{}", headers), String.class);

        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40001);
    }

    @Test
    void postInvalidUserType_returns40001() throws Exception {
        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);
        Map<String, Object> body = baseBody("sp_test_u_invtype", "枚举");
        body.put("sUserType", "火星");

        ResponseEntity<String> resp = rest.exchange(
                url(), HttpMethod.POST, new HttpEntity<>(body, headers), String.class);

        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40001);
    }

    @Test
    void postInvalidLanguage_returns40001() throws Exception {
        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);
        Map<String, Object> body = baseBody("sp_test_u_invlang", "枚举");
        body.put("sLanguage", "ja");

        ResponseEntity<String> resp = rest.exchange(
                url(), HttpMethod.POST, new HttpEntity<>(body, headers), String.class);

        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40001);
    }

    @Test
    void postDuplicateUserNo_returns40020() throws Exception {
        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);
        Map<String, Object> first = baseBody("sp_test_u_dup", "首次");
        ResponseEntity<String> r1 = rest.exchange(url(), HttpMethod.POST, new HttpEntity<>(first, headers), String.class);
        assertThat(objectMapper.readTree(r1.getBody()).get("code").asInt()).isZero();

        Map<String, Object> dup = baseBody("sp_test_u_dup", "重复");
        dup.put("sUserName", "sp_test_u_dup_other");
        ResponseEntity<String> r2 = rest.exchange(url(), HttpMethod.POST, new HttpEntity<>(dup, headers), String.class);
        assertThat(objectMapper.readTree(r2.getBody()).get("code").asInt()).isEqualTo(40020);
    }

    @Test
    void postStaffNotFound_returns40022() throws Exception {
        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);
        Map<String, Object> body = baseBody("sp_test_u_nostaff", "缺职员");
        body.put("iStaffId", 99999990);

        ResponseEntity<String> resp = rest.exchange(
                url(), HttpMethod.POST, new HttpEntity<>(body, headers), String.class);

        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40022);
    }

    @Test
    void postPermissionCategoryNotFound_returns40023() throws Exception {
        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);
        Map<String, Object> body = baseBody("sp_test_u_nocat", "缺权限");
        body.put("permissionCategoryIds", List.of(99999991));

        ResponseEntity<String> resp = rest.exchange(
                url(), HttpMethod.POST, new HttpEntity<>(body, headers), String.class);

        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40023);
    }

    @Test
    void postWithoutJwt_returns20001() throws Exception {
        HttpHeaders headers = jsonHeaders();
        Map<String, Object> body = baseBody("sp_test_u_nojwt", "无JWT");

        ResponseEntity<String> resp = rest.exchange(
                url(), HttpMethod.POST, new HttpEntity<>(body, headers), String.class);

        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(20001);
        Integer count = jdbcTemplate.queryForObject(
                "SELECT COUNT(1) FROM tUser WHERE sUserNo = 'sp_test_u_nojwt'", Integer.class);
        assertThat(count).isZero();
    }

    @Test
    void postTamperedJwt_returns20001() throws Exception {
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer not.a.real.jwt");
        Map<String, Object> body = baseBody("sp_test_u_tamper", "伪JWT");

        ResponseEntity<String> resp = rest.exchange(
                url(), HttpMethod.POST, new HttpEntity<>(body, headers), String.class);

        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(20001);
        Integer count = jdbcTemplate.queryForObject(
                "SELECT COUNT(1) FROM tUser WHERE sUserNo = 'sp_test_u_tamper'", Integer.class);
        assertThat(count).isZero();
    }

    @Test
    void putValidBody_with_jwt_returns200_andUpdates() throws Exception {
        Integer staffId = insertStaff("sp_test_pst1", "员工1");
        Integer cat1 = insertCategory("sp_test_pc_p1", "权限1");
        Integer cat2 = insertCategory("sp_test_pc_p2", "权限2");
        Integer userId = insertUserWithPerms("sp_test_u_putorig", "原用户", staffId, cat1);

        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);
        Map<String, Object> body = baseBody("sp_test_u_putorig", "原用户改名");
        body.put("permissionCategoryIds", List.of(cat1, cat2));

        ResponseEntity<String> resp = rest.exchange(
                idUrl(userId), HttpMethod.PUT, new HttpEntity<>(body, headers), String.class);

        JsonNode jb = objectMapper.readTree(resp.getBody());
        assertThat(jb.get("code").asInt()).isZero();
        assertThat(jb.get("data").get("iIncrement").asInt()).isEqualTo(userId);

        Map<String, Object> row = jdbcTemplate.queryForMap(
                "SELECT sUserName, sPasswordHash, sCreatedBy FROM tUser WHERE iIncrement = ?", userId);
        assertThat(row.get("sUserName")).isEqualTo("原用户改名");
        assertThat((String) row.get("sPasswordHash")).startsWith("$2a$");
        assertThat(row.get("sCreatedBy")).isEqualTo("ORIG_CREATOR");

        Integer permCount = jdbcTemplate.queryForObject(
                "SELECT COUNT(1) FROM tUserPermission WHERE iUserId = ?", Integer.class, userId);
        assertThat(permCount).isEqualTo(2);
    }

    @Test
    void putNonExistentId_returns40400() throws Exception {
        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);
        Map<String, Object> body = baseBody("sp_test_u_no", "无");

        ResponseEntity<String> resp = rest.exchange(
                idUrl(99999990), HttpMethod.PUT, new HttpEntity<>(body, headers), String.class);

        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40400);
    }

    @Test
    void putAlreadyDeletedId_returns40400() throws Exception {
        Integer userId = insertUserWithPerms("sp_test_u_deleted", "已删", null, null);
        jdbcTemplate.update("UPDATE tUser SET bDeleted = 1 WHERE iIncrement = ?", userId);
        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);

        ResponseEntity<String> resp = rest.exchange(
                idUrl(userId), HttpMethod.PUT, new HttpEntity<>(baseBody("sp_test_u_deleted", "改"), headers),
                String.class);

        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40400);
    }

    @Test
    void putInvalidUserType_returns40001() throws Exception {
        Integer userId = insertUserWithPerms("sp_test_u_pinvtype", "原", null, null);
        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);
        Map<String, Object> body = baseBody("sp_test_u_pinvtype", "改");
        body.put("sUserType", "火星");

        ResponseEntity<String> resp = rest.exchange(
                idUrl(userId), HttpMethod.PUT, new HttpEntity<>(body, headers), String.class);

        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40001);
    }

    @Test
    void putDuplicateUserNo_returns40020() throws Exception {
        Integer u1 = insertUserWithPerms("sp_test_u_pdupA", "AAA", null, null);
        Integer u2 = insertUserWithPerms("sp_test_u_pdupB", "BBB", null, null);
        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);
        Map<String, Object> body = baseBody("sp_test_u_pdupA", "改成 A");

        ResponseEntity<String> resp = rest.exchange(
                idUrl(u2), HttpMethod.PUT, new HttpEntity<>(body, headers), String.class);

        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40020);
    }

    @Test
    void putStaffNotFound_returns40022() throws Exception {
        Integer userId = insertUserWithPerms("sp_test_u_pstaff", "原", null, null);
        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);
        Map<String, Object> body = baseBody("sp_test_u_pstaff", "改");
        body.put("iStaffId", 99999990);

        ResponseEntity<String> resp = rest.exchange(
                idUrl(userId), HttpMethod.PUT, new HttpEntity<>(body, headers), String.class);

        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40022);
    }

    @Test
    void putPermissionCategoryNotFound_returns40023() throws Exception {
        Integer userId = insertUserWithPerms("sp_test_u_pperm", "原", null, null);
        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);
        Map<String, Object> body = baseBody("sp_test_u_pperm", "改");
        body.put("permissionCategoryIds", List.of(99999991));

        ResponseEntity<String> resp = rest.exchange(
                idUrl(userId), HttpMethod.PUT, new HttpEntity<>(body, headers), String.class);

        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40023);
    }

    @Test
    void putWithEmptyPermissionIds_clearsAssociations() throws Exception {
        Integer cat1 = insertCategory("sp_test_pc_e1", "权限");
        Integer userId = insertUserWithPerms("sp_test_u_pclear", "原", null, cat1);

        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);
        Map<String, Object> body = baseBody("sp_test_u_pclear", "改");
        body.remove("permissionCategoryIds");

        ResponseEntity<String> resp = rest.exchange(
                idUrl(userId), HttpMethod.PUT, new HttpEntity<>(body, headers), String.class);

        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isZero();
        Integer permCount = jdbcTemplate.queryForObject(
                "SELECT COUNT(1) FROM tUserPermission WHERE iUserId = ?", Integer.class, userId);
        assertThat(permCount).isZero();
        String passHash = jdbcTemplate.queryForObject(
                "SELECT sPasswordHash FROM tUser WHERE iIncrement = ?", String.class, userId);
        assertThat(passHash).startsWith("$2a$");
    }

    @Test
    void putWithoutJwt_returns20001() throws Exception {
        Integer userId = insertUserWithPerms("sp_test_u_pnojwt", "原", null, null);
        HttpHeaders headers = jsonHeaders();
        Map<String, Object> body = baseBody("sp_test_u_pnojwt", "改");

        ResponseEntity<String> resp = rest.exchange(
                idUrl(userId), HttpMethod.PUT, new HttpEntity<>(body, headers), String.class);

        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(20001);
        String name = jdbcTemplate.queryForObject(
                "SELECT sUserName FROM tUser WHERE iIncrement = ?", String.class, userId);
        assertThat(name).isEqualTo("原");
    }

    @Test
    void putTamperedJwt_returns20001() throws Exception {
        Integer userId = insertUserWithPerms("sp_test_u_ptamper", "原", null, null);
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer not.a.real.jwt");
        Map<String, Object> body = baseBody("sp_test_u_ptamper", "改");

        ResponseEntity<String> resp = rest.exchange(
                idUrl(userId), HttpMethod.PUT, new HttpEntity<>(body, headers), String.class);

        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(20001);
        String name = jdbcTemplate.queryForObject(
                "SELECT sUserName FROM tUser WHERE iIncrement = ?", String.class, userId);
        assertThat(name).isEqualTo("原");
    }

    @Test
    void getDefaults_with_jwt_returns200_andList() throws Exception {
        insertUserWithPerms("sp_test_lst_1", "查询1", null, null);
        insertUserWithPerms("sp_test_lst_2", "查询2", null, null);
        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);

        ResponseEntity<String> resp = rest.exchange(
                listUrl(""), HttpMethod.GET, new HttpEntity<>(headers), String.class);

        JsonNode jb = objectMapper.readTree(resp.getBody());
        assertThat(jb.get("code").asInt()).isZero();
        assertThat(jb.get("data").get("records").isArray()).isTrue();
        assertThat(jb.get("data").get("total").asInt()).isPositive();
        assertThat(jb.get("data").get("pageSize").asInt()).isEqualTo(20);
    }

    @Test
    void getKeywordContains_filtersByUsername() throws Exception {
        insertUserWithPerms("sp_test_lst_kw1", "包含查询用户", null, null);
        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);

        ResponseEntity<String> resp = rest.exchange(
                listUrl("?field=用户名&match=包含&value=包含查询"), HttpMethod.GET, new HttpEntity<>(headers), String.class);

        JsonNode data = objectMapper.readTree(resp.getBody()).get("data");
        for (JsonNode node : data.get("records")) {
            assertThat(node.get("sUserName").asText()).contains("包含查询");
        }
    }

    @Test
    void getKeywordEquals_filtersExact() throws Exception {
        insertUserWithPerms("sp_test_lst_eq", "等于精确", null, null);
        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);

        ResponseEntity<String> resp = rest.exchange(
                listUrl("?field=用户号&match=等于&value=sp_test_lst_eq"), HttpMethod.GET, new HttpEntity<>(headers), String.class);

        JsonNode records = objectMapper.readTree(resp.getBody()).get("data").get("records");
        assertThat(records.size()).isEqualTo(1);
        assertThat(records.get(0).get("sUserNo").asText()).isEqualTo("sp_test_lst_eq");
    }

    @Test
    void getInvalidField_returns40001() throws Exception {
        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);

        ResponseEntity<String> resp = rest.exchange(
                listUrl("?field=未知"), HttpMethod.GET, new HttpEntity<>(headers), String.class);

        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40001);
    }

    @Test
    void getPageSizeExceeds100_returns40002() throws Exception {
        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);

        ResponseEntity<String> resp = rest.exchange(
                listUrl("?pageSize=200"), HttpMethod.GET, new HttpEntity<>(headers), String.class);

        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(40002);
    }

    @Test
    void getNoMatch_returnsEmptyArray() throws Exception {
        String token = testJwtHelper.signFor("ADMIN001");
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer " + token);

        ResponseEntity<String> resp = rest.exchange(
                listUrl("?field=用户号&match=等于&value=不存在的用户号XYZ"), HttpMethod.GET, new HttpEntity<>(headers), String.class);

        JsonNode data = objectMapper.readTree(resp.getBody()).get("data");
        assertThat(data.get("records").isArray()).isTrue();
        assertThat(data.get("records").size()).isZero();
        assertThat(data.get("total").asInt()).isZero();
    }

    @Test
    void getWithoutJwt_returns20001() throws Exception {
        HttpHeaders headers = jsonHeaders();
        ResponseEntity<String> resp = rest.exchange(
                listUrl(""), HttpMethod.GET, new HttpEntity<>(headers), String.class);
        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(20001);
    }

    @Test
    void getTamperedJwt_returns20001() throws Exception {
        HttpHeaders headers = jsonHeaders();
        headers.set("Authorization", "Bearer not.a.real.jwt");
        ResponseEntity<String> resp = rest.exchange(
                listUrl(""), HttpMethod.GET, new HttpEntity<>(headers), String.class);
        assertThat(objectMapper.readTree(resp.getBody()).get("code").asInt()).isEqualTo(20001);
    }

    private String listUrl(String querySuffix) {
        return "http://localhost:" + port + "/api/usr/users" + querySuffix;
    }

    private String idUrl(Integer id) {
        return "http://localhost:" + port + "/api/usr/users/" + id;
    }

    private Integer insertUserWithPerms(String userNo, String userName, Integer staffId, Integer catId) {
        jdbcTemplate.update(
                "INSERT INTO tUser (sBrandsId, sSubsidiaryId, tCreateDate, sUserNo, sUserName, iStaffId, "
                        + "sUserType, sLanguage, bCanModifyDocs, sPasswordHash, sCreatedBy, bDeleted) "
                        + "VALUES ('XLY','XLY', NOW(), ?, ?, ?, '普通用户', 'zh', 0, "
                        + "'$2a$10$origHashOrigHashOrigHashOrigHashOrigHashOrigHashOrig', 'ORIG_CREATOR', 0)",
                userNo, userName, staffId);
        Integer userId = jdbcTemplate.queryForObject(
                "SELECT iIncrement FROM tUser WHERE sUserNo = ?", Integer.class, userNo);
        if (catId != null) {
            jdbcTemplate.update(
                    "INSERT INTO tUserPermission (sBrandsId, sSubsidiaryId, tCreateDate, iUserId, iCategoryId, sCreatedBy) "
                            + "VALUES ('XLY','XLY', NOW(), ?, ?, 'ORIG_CREATOR')",
                    userId, catId);
        }
        return userId;
    }

    private Integer insertStaff(String staffNo, String name) {
        jdbcTemplate.update(
                "INSERT INTO tStaff (sBrandsId, sSubsidiaryId, tCreateDate, sStaffNo, sStaffName, sCreatedBy, bDeleted) "
                        + "VALUES ('XLY','XLY', NOW(), ?, ?, 'STUB_ADMIN', 0)", staffNo, name);
        return jdbcTemplate.queryForObject(
                "SELECT iIncrement FROM tStaff WHERE sStaffNo = ?", Integer.class, staffNo);
    }

    private Integer insertCategory(String code, String name) {
        jdbcTemplate.update(
                "INSERT INTO tPermissionCategory (sBrandsId, sSubsidiaryId, tCreateDate, sCategoryCode, sCategoryName, "
                        + "iSortOrder, sCreatedBy, bDeleted) "
                        + "VALUES ('XLY','XLY', NOW(), ?, ?, 0, 'STUB_ADMIN', 0)", code, name);
        return jdbcTemplate.queryForObject(
                "SELECT iIncrement FROM tPermissionCategory WHERE sCategoryCode = ?", Integer.class, code);
    }

    private static Map<String, Object> baseBody(String userNo, String userName) {
        Map<String, Object> m = new HashMap<>();
        m.put("sUserNo", userNo);
        m.put("sUserName", userName);
        m.put("sUserType", "普通用户");
        m.put("sLanguage", "zh");
        m.put("bCanModifyDocs", false);
        return m;
    }

    private static HttpHeaders jsonHeaders() {
        HttpHeaders h = new HttpHeaders();
        h.setContentType(MediaType.APPLICATION_JSON);
        return h;
    }

    private String url() {
        return "http://localhost:" + port + "/api/usr/users";
    }
}
