package com.zioinfo.hrm.uiws.system.service;

import com.zioinfo.hrm.uiws.common.UiwsApiException;
import com.zioinfo.hrm.uiws.common.UiwsErrorCode;
import com.zioinfo.hrm.uiws.system.dto.PageResponse;
import com.zioinfo.hrm.uiws.system.dto.RoleDto;
import com.zioinfo.hrm.uiws.system.dto.RoleMenuDto;
import com.zioinfo.hrm.uiws.system.mapper.MenuMapper;
import com.zioinfo.hrm.uiws.system.mapper.RoleMapper;
import com.zioinfo.hrm.uiws.system.mapper.RoleMenuMapper;
import com.zioinfo.hrm.uiws.system.model.SysMenu;
import com.zioinfo.hrm.uiws.system.model.SysRole;
import com.zioinfo.hrm.uiws.system.model.SysRoleMenu;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 2.5 메뉴생성(role-menus). 권한 목록 + 권한별 메뉴 매핑 조회/저장.
 * 조회는 전체 사용중 메뉴 기준으로 매핑 여부(read/write)를 합쳐 반환.
 */
@Service
@RequiredArgsConstructor
public class RoleMenuService {

    private final RoleMapper roleMapper;
    private final RoleMenuMapper roleMenuMapper;
    private final MenuMapper menuMapper;

    @Transactional(readOnly = true)
    public PageResponse<RoleDto> listRoles(int page, int size) {
        List<RoleDto> content = roleMapper.search(null, page * size, size).stream()
                .map(this::toRoleDto).toList();
        return PageResponse.of(content, roleMapper.countSearch(null), page, size);
    }

    @Transactional(readOnly = true)
    public List<RoleMenuDto> getRoleMenus(String roleId) {
        ensureRole(roleId);
        Map<String, SysRoleMenu> mapped = new LinkedHashMap<>();
        for (SysRoleMenu rm : roleMenuMapper.findByRoleId(roleId)) {
            mapped.put(rm.getMenuId(), rm);
        }
        List<SysMenu> allMenus = menuMapper.findAllOrdered();
        return allMenus.stream().map(m -> {
            SysRoleMenu rm = mapped.get(m.getMenuId());
            String readYn = rm != null ? rm.getReadYn() : "N";
            String writeYn = rm != null ? rm.getWriteYn() : "N";
            return new RoleMenuDto(m.getMenuId(), m.getMenuNm(), readYn, writeYn);
        }).toList();
    }

    /** 전체 치환 저장: read/write 중 하나라도 'Y'면 매핑 보존, 둘 다 'N'이면 제거. */
    @Transactional
    public void saveRoleMenus(String roleId, List<RoleMenuDto> menus) {
        ensureRole(roleId);
        String actor = SysActor.id();
        roleMenuMapper.deleteByRoleId(roleId);
        if (menus == null) {
            return;
        }
        for (RoleMenuDto dto : menus) {
            boolean read = "Y".equals(dto.readYn());
            boolean write = "Y".equals(dto.writeYn());
            if (!read && !write) {
                continue;
            }
            SysRoleMenu rm = new SysRoleMenu();
            rm.setRoleId(roleId);
            rm.setMenuId(dto.menuId());
            rm.setReadYn(read ? "Y" : "N");
            rm.setWriteYn(write ? "Y" : "N");
            rm.setCreatedBy(actor);
            roleMenuMapper.insert(rm);
        }
    }

    private RoleDto toRoleDto(SysRole r) {
        return new RoleDto(r.getRoleId(), r.getRoleNm(), r.getRoleDesc(), r.getUseYn());
    }

    private void ensureRole(String roleId) {
        if (!roleMapper.existsById(roleId)) {
            throw new UiwsApiException(UiwsErrorCode.ROLE_NOT_FOUND);
        }
    }
}
