package com.ga.api.service.org;

import com.ga.common.exception.BizException;
import com.ga.common.exception.ErrorCode;
import com.ga.core.mapper.org.OrganizationMapper;
import com.ga.core.vo.org.OrganizationResp;
import com.ga.core.vo.org.OrganizationSaveReq;
import com.ga.core.vo.org.OrganizationVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
@RequiredArgsConstructor
public class OrganizationService {

    private final OrganizationMapper mapper;

    @Transactional(readOnly = true)
    public List<OrganizationResp> getTree() {
        List<OrganizationResp> flat = mapper.selectAllForTree();
        return buildTree(flat);
    }

    @Transactional(readOnly = true)
    public List<OrganizationResp> list(String keyword, String orgType, String isActive) {
        return mapper.selectList(keyword, orgType, isActive);
    }

    @Transactional(readOnly = true)
    public OrganizationVO get(Long orgId) {
        OrganizationVO vo = mapper.selectById(orgId);
        if (vo == null) throw new BizException(ErrorCode.NOT_FOUND);
        return vo;
    }

    @Transactional
    public Long create(OrganizationSaveReq req) {
        OrganizationVO vo = toVO(req, null);
        mapper.insert(vo);
        return vo.getOrgId();
    }

    @Transactional
    public void update(Long orgId, OrganizationSaveReq req) {
        get(orgId);
        OrganizationVO vo = toVO(req, orgId);
        mapper.update(vo);
    }

    private OrganizationVO toVO(OrganizationSaveReq req, Long orgId) {
        OrganizationVO vo = new OrganizationVO();
        vo.setOrgId(orgId);
        vo.setOrgName(req.getOrgName());
        vo.setParentOrgId(req.getParentOrgId());
        vo.setOrgType(req.getOrgType());
        vo.setOrgLevel(req.getOrgLevel());
        vo.setRegion(req.getRegion());
        vo.setEffectiveFrom(req.getEffectiveFrom());
        vo.setEffectiveTo(req.getEffectiveTo());
        vo.setIsActive(req.getIsActive());
        return vo;
    }

    @Transactional
    public void delete(Long orgId) {
        if (mapper.countChildren(orgId) > 0) {
            throw new BizException(ErrorCode.DEPENDENT_DATA, "하위 조직이 있어 삭제할 수 없습니다");
        }
        if (mapper.countAgents(orgId) > 0) {
            throw new BizException(ErrorCode.DEPENDENT_DATA, "소속 설계사가 있어 삭제할 수 없습니다");
        }
        mapper.deleteById(orgId);
    }

    private List<OrganizationResp> buildTree(List<OrganizationResp> flat) {
        Map<Long, OrganizationResp> byId = new LinkedHashMap<>();
        for (OrganizationResp o : flat) byId.put(o.getOrgId(), o);
        List<OrganizationResp> roots = new ArrayList<>();
        for (OrganizationResp o : flat) {
            if (o.getParentOrgId() == null) {
                roots.add(o);
            } else {
                OrganizationResp parent = byId.get(o.getParentOrgId());
                if (parent != null) parent.getChildren().add(o);
                else roots.add(o);
            }
        }
        return roots;
    }
}
