package com.erp.service;

import com.erp.common.BaseService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class RoleService extends BaseService {

    // ──────────────────────────────────────────────────
    // 권한 그룹 CRUD
    // ──────────────────────────────────────────────────

    public List<Map<String, Object>> getRoleGroups(Map<String, Object> params) {
        return sqlSession.selectList("role.getRoleGroupList", params);
    }

    public Map<String, Object> getRoleGroupById(Map<String, Object> params) {
        return sqlSession.selectOne("role.getRoleGroupInfo", params);
    }

    @Transactional
    public Map<String, Object> createRoleGroup(Map<String, Object> params) {
        sqlSession.insert("role.insertRoleGroup", params);
        Object objid = params.get("objid");
        Map<String, Object> findParams = new HashMap<>();
        findParams.put("objid", objid);
        return sqlSession.selectOne("role.getRoleGroupInfo", findParams);
    }

    @Transactional
    public Map<String, Object> updateRoleGroup(Map<String, Object> params) {
        sqlSession.update("role.updateRoleGroup", params);
        return sqlSession.selectOne("role.getRoleGroupInfo", params);
    }

    @Transactional
    public void deleteRoleGroup(Map<String, Object> params) {
        Object objid = params.get("objid");
        // 연관 데이터 먼저 삭제
        Map<String, Object> memberParams = new HashMap<>();
        memberParams.put("master_objid", objid);
        sqlSession.delete("role.deleteAllRoleMembers", memberParams);

        Map<String, Object> menuParams = new HashMap<>();
        menuParams.put("auth_objid", objid);
        sqlSession.delete("role.deleteMenuPermissions", menuParams);

        sqlSession.delete("role.deleteRoleGroup", params);
        log.info("권한 그룹 삭제 완료: objid={}", objid);
    }

    // ──────────────────────────────────────────────────
    // 멤버 관리 (권한있는 / 권한없는 직원)
    // ──────────────────────────────────────────────────

    public List<Map<String, Object>> getRoleMembers(Map<String, Object> params) {
        return sqlSession.selectList("role.getRoleMemberList", params);
    }

    public List<Map<String, Object>> getRoleNonMembers(Map<String, Object> params) {
        return sqlSession.selectList("role.getRoleNonMemberList", params);
    }

    @Transactional
    public void addRoleMembers(Map<String, Object> params) {
        List<String> userIds = getStringList(params, "user_ids");
        if (userIds.isEmpty()) return;

        Map<String, Object> insertParams = new HashMap<>(params);
        insertParams.put("userIds", userIds);
        sqlSession.insert("role.insertRoleMembers", insertParams);
    }

    /**
     * 개별 멤버 추가 (이미지: "<--추가" 1건)
     */
    @Transactional
    public boolean addSingleRoleMember(String masterObjid, String userId, String writer) {
        Map<String, Object> params = new HashMap<>();
        params.put("master_objid", masterObjid);
        params.put("user_id", userId);
        params.put("writer", writer != null ? writer : "SYSTEM");
        params.put("objid", masterObjid + "_" + userId);
        int affected = sqlSession.insert("role.insertSingleRoleMember", params);
        log.info("개별 멤버 추가: master={}, user={}, inserted={}", masterObjid, userId, affected);
        return affected > 0;
    }

    /**
     * 개별 멤버 제거 (이미지: "-->삭제" 1건)
     */
    @Transactional
    public boolean removeSingleRoleMember(String masterObjid, String userId) {
        Map<String, Object> params = new HashMap<>();
        params.put("master_objid", masterObjid);
        params.put("user_id", userId);
        int affected = sqlSession.delete("role.deleteSingleRoleMember", params);
        log.info("개별 멤버 제거: master={}, user={}, deleted={}", masterObjid, userId, affected);
        return affected > 0;
    }

    @Transactional
    public void updateRoleMembers(Map<String, Object> params) {
        Object masterObjid = params.get("master_objid");
        List<String> newUserIds = getStringList(params, "user_ids");
        String writer = (String) params.getOrDefault("writer", "SYSTEM");

        // 기존 멤버 조회
        Map<String, Object> findParams = new HashMap<>();
        findParams.put("master_objid", masterObjid);
        List<Map<String, Object>> existingMembers = sqlSession.selectList("role.getRoleMemberList", findParams);
        List<String> existingIds = existingMembers.stream()
                .map(m -> (String) m.get("user_id"))
                .collect(Collectors.toList());

        List<String> toAdd = newUserIds.stream()
                .filter(id -> !existingIds.contains(id))
                .collect(Collectors.toList());
        List<String> toRemove = existingIds.stream()
                .filter(id -> !newUserIds.contains(id))
                .collect(Collectors.toList());

        if (!toAdd.isEmpty()) {
            Map<String, Object> addParams = new HashMap<>();
            addParams.put("master_objid", masterObjid);
            addParams.put("userIds", toAdd);
            addParams.put("writer", writer);
            sqlSession.insert("role.insertRoleMembers", addParams);
        }
        if (!toRemove.isEmpty()) {
            Map<String, Object> removeParams = new HashMap<>();
            removeParams.put("master_objid", masterObjid);
            removeParams.put("userIds", toRemove);
            sqlSession.delete("role.deleteRoleMembers", removeParams);
        }
        log.info("권한 그룹 멤버 업데이트: masterObjid={}, added={}, removed={}",
                masterObjid, toAdd.size(), toRemove.size());
    }

    @Transactional
    public void removeRoleMembers(Map<String, Object> params) {
        List<String> userIds = getStringList(params, "user_ids");
        if (userIds.isEmpty()) return;

        Map<String, Object> deleteParams = new HashMap<>(params);
        deleteParams.put("userIds", userIds);
        sqlSession.delete("role.deleteRoleMembers", deleteParams);
    }

    // ──────────────────────────────────────────────────
    // 메뉴 권한 관리
    // ──────────────────────────────────────────────────

    public List<Map<String, Object>> getMenuPermissions(Map<String, Object> params) {
        return sqlSession.selectList("role.getMenuPermissionList", params);
    }

    /**
     * 메뉴 권한 전체 설정 (기존 삭제 후 재등록)
     * permissions 각 요소에 menuObjid, createYn, readYn, updateYn, deleteYn 포함
     */
    @Transactional
    public void setMenuPermissions(Map<String, Object> params) {
        Object authObjid = params.get("auth_objid");
        List<?> permissions = (List<?>) params.get("permissions");
        String writer = (String) params.getOrDefault("writer", "SYSTEM");

        // 기존 권한 전체 삭제 후 재등록
        Map<String, Object> deleteParams = new HashMap<>();
        deleteParams.put("auth_objid", authObjid);
        sqlSession.delete("role.deleteMenuPermissions", deleteParams);

        if (permissions != null && !permissions.isEmpty()) {
            // CRUD 중 하나라도 Y인 것만 저장 (모두 N이면 의미 없음)
            List<?> nonEmpty = permissions.stream()
                    .filter(p -> p instanceof Map<?, ?>)
                    .filter(p -> {
                        Map<?, ?> m = (Map<?, ?>) p;
                        return "Y".equals(m.get("createYn"))
                                || "Y".equals(m.get("readYn"))
                                || "Y".equals(m.get("updateYn"))
                                || "Y".equals(m.get("deleteYn"));
                    })
                    .collect(Collectors.toList());

            if (!nonEmpty.isEmpty()) {
                Map<String, Object> insertParams = new HashMap<>();
                insertParams.put("auth_objid", authObjid);
                insertParams.put("permissions", nonEmpty);
                insertParams.put("writer", writer);
                sqlSession.insert("role.insertMenuPermissions", insertParams);
            }
        }
        log.info("메뉴 권한 설정 완료: authObjid={}, count={}", authObjid,
                permissions != null ? permissions.size() : 0);
    }

    /**
     * 개별 메뉴 권한 upsert (이미지: 체크 즉시 반영)
     * 전달된 필드만 업데이트, 미전달 필드는 기존값 유지 (null-safe)
     * 모든 CRUD가 N이면 row 제거
     */
    @Transactional
    public Map<String, Object> toggleMenuPermission(
            String authObjid, String menuObjid,
            String createYn, String readYn, String updateYn, String deleteYn,
            String writer) {

        // 기존 row 조회
        Map<String, Object> findParams = new HashMap<>();
        findParams.put("auth_objid", authObjid);
        findParams.put("menu_objid", menuObjid);
        Map<String, Object> existing = sqlSession.selectOne("role.getMenuPermissionByMenu", findParams);

        // 최종값 계산: 전달값 우선, 없으면 기존값, 없으면 N
        String finalCreate = resolve(createYn, existing, "create_yn");
        String finalRead   = resolve(readYn,   existing, "read_yn");
        String finalUpdate = resolve(updateYn, existing, "update_yn");
        String finalDelete = resolve(deleteYn, existing, "delete_yn");

        // 모두 N이면 row 제거
        if ("N".equals(finalCreate) && "N".equals(finalRead)
                && "N".equals(finalUpdate) && "N".equals(finalDelete)) {
            if (existing != null) {
                sqlSession.delete("role.deleteSingleMenuPermission", findParams);
            }
            Map<String, Object> result = new LinkedHashMap<>();
            result.put("master_objid", authObjid);
            result.put("menu_objid", menuObjid);
            result.put("create_yn", "N");
            result.put("read_yn", "N");
            result.put("update_yn", "N");
            result.put("delete_yn", "N");
            return result;
        }

        // upsert
        Map<String, Object> params = new HashMap<>();
        params.put("objid", authObjid + "_" + menuObjid);
        params.put("auth_objid", authObjid);
        params.put("menu_objid", menuObjid);
        params.put("create_yn", finalCreate);
        params.put("read_yn", finalRead);
        params.put("update_yn", finalUpdate);
        params.put("delete_yn", finalDelete);
        params.put("writer", writer != null ? writer : "SYSTEM");
        sqlSession.insert("role.upsertMenuPermission", params);

        log.info("메뉴 권한 토글: auth={}, menu={}, CRUD={}/{}/{}/{}",
                authObjid, menuObjid, finalCreate, finalRead, finalUpdate, finalDelete);

        return sqlSession.selectOne("role.getMenuPermissionByMenu", findParams);
    }

    private String resolve(String newVal, Map<String, Object> existing, String key) {
        if (newVal != null) return newVal;
        if (existing != null && existing.get(key) != null) return (String) existing.get(key);
        return "N";
    }

    // ──────────────────────────────────────────────────
    // 메뉴 목록 / 사용자 권한 그룹
    // ──────────────────────────────────────────────────

    public List<Map<String, Object>> getAllMenus(Map<String, Object> params) {
        return sqlSession.selectList("role.getMenuList", params);
    }

    public List<Map<String, Object>> getUserRoleGroups(Map<String, Object> params) {
        return sqlSession.selectList("role.getUserRoleGroupList", params);
    }

    // ──────────────────────────────────────────────────
    // 통합 워크스페이스 (이미지: 권한 그룹 선택 시 한 번에 로드)
    // ──────────────────────────────────────────────────

    /**
     * 권한 그룹 선택 시 화면에 필요한 모든 정보를 한 번에 조회
     * - 권한 그룹 정보
     * - 권한있는 직원
     * - 권한없는 직원
     * - 전체 메뉴 (트리 원천)
     * - 현재 권한 그룹의 메뉴 권한
     */
    public Map<String, Object> getRoleWorkspace(String roleId) {
        Map<String, Object> findParams = new HashMap<>();
        findParams.put("objid", roleId);
        Map<String, Object> group = sqlSession.selectOne("role.getRoleGroupInfo", findParams);
        if (group == null) return null;

        String companyCode = (String) group.get("company_code");

        // 권한있는 직원
        Map<String, Object> memberParams = new HashMap<>();
        memberParams.put("master_objid", roleId);
        List<Map<String, Object>> members = sqlSession.selectList("role.getRoleMemberList", memberParams);

        // 권한없는 직원 (같은 회사 기준)
        Map<String, Object> nonMemberParams = new HashMap<>();
        nonMemberParams.put("master_objid", roleId);
        nonMemberParams.put("company_code", companyCode);
        nonMemberParams.put("status_active", true);
        List<Map<String, Object>> nonMembers = sqlSession.selectList("role.getRoleNonMemberList", nonMemberParams);

        // 전체 메뉴 (해당 회사 + 공통 '*')
        Map<String, Object> menuParams = new HashMap<>();
        menuParams.put("company_code", companyCode);
        List<Map<String, Object>> allMenus = sqlSession.selectList("role.getMenuList", menuParams);

        // 현재 권한
        Map<String, Object> permParams = new HashMap<>();
        permParams.put("auth_objid", roleId);
        List<Map<String, Object>> permissions = sqlSession.selectList("role.getMenuPermissionList", permParams);

        Map<String, Object> result = new LinkedHashMap<>();
        result.put("group", group);
        result.put("members", members);
        result.put("nonMembers", nonMembers);
        result.put("menus", allMenus);
        result.put("permissions", permissions);
        return result;
    }

    // ──────────────────────────────────────────────────
    // 내부 유틸
    // ──────────────────────────────────────────────────

    @SuppressWarnings("unchecked")
    private List<String> getStringList(Map<String, Object> params, String key) {
        Object val = params.get(key);
        if (val instanceof List<?> list) {
            return list.stream()
                    .filter(item -> item instanceof String)
                    .map(item -> (String) item)
                    .collect(Collectors.toList());
        }
        return List.of();
    }
}
