package kr.itn.itnhub.project;
import kr.itn.itnhub.dashboard.DashboardOrgRow;
import kr.itn.itnhub.dashboard.DashboardService;
import kr.itn.itnhub.org.OrgNotFoundException;
import kr.itn.itnhub.org.OrganizationMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 사업관리 화면. 3단계 법률검토로 진행할 기관 현황을 한 곳에 모아 보여주고, 기관마다
* "신청 확인 연락" 이력과 최종 보고서를 관리한다(요청자 요구: 별도 메뉴로 구축 + 연락 부분 이력관리
* + 기관별 최종 보고서 업로드).
*
*
기관 현황 숫자는 대시보드와 같은 집계를 그대로 쓴다 - 두 화면이 다른 숫자를 보여주면
* 어느 쪽이 맞는지 확인할 방법이 없기 때문이다.
*/
@Service
public class ProjectService {
private final DashboardService dashboardService;
private final ProjectMapper mapper;
private final OrganizationMapper orgMapper;
public ProjectService(DashboardService dashboardService, ProjectMapper mapper,
OrganizationMapper orgMapper) {
this.dashboardService = dashboardService;
this.mapper = mapper;
this.orgMapper = orgMapper;
}
public List rows() {
Map side = new HashMap<>();
for (ProjectMapper.ProjectSideInfo info : mapper.findSideInfo()) {
side.put(info.orgId(), info);
}
List orgs = dashboardService.dashboard().orgs();
List rows = new ArrayList<>(orgs.size());
for (DashboardOrgRow org : orgs) {
ProjectMapper.ProjectSideInfo info = side.get(org.id());
rows.add(new ProjectRow(org,
info == null ? null : info.lastContactedOn(),
info == null ? 0 : info.contactCount(),
info == null ? 0 : info.reportCount()));
}
return rows;
}
public List logs(Long orgId) {
requireOrg(orgId);
return mapper.findLogsByOrg(orgId);
}
@Transactional
public List addLog(Long orgId, ContactLogRequest request, String author) {
requireOrg(orgId);
mapper.insertLog(orgId, request.contactedOn(), request.method(), request.summary(), author);
return mapper.findLogsByOrg(orgId);
}
@Transactional
public List updateLog(Long orgId, Long logId, ContactLogRequest request) {
requireOrg(orgId);
if (mapper.updateLog(orgId, logId, request.contactedOn(), request.method(),
request.summary()) == 0) {
throw new OrgNotFoundException("연락 이력을 찾을 수 없습니다: " + logId);
}
return mapper.findLogsByOrg(orgId);
}
@Transactional
public void deleteLog(Long orgId, Long logId) {
requireOrg(orgId);
if (mapper.deleteLog(orgId, logId) == 0) {
throw new OrgNotFoundException("연락 이력을 찾을 수 없습니다: " + logId);
}
}
public List reports(Long orgId) {
requireOrg(orgId);
return mapper.findReportsByOrg(orgId);
}
/** 같은 기관에 여러 번 올릴 수 있다(개정판). 최신순으로 목록에 쌓인다. */
@Transactional
public List addReport(Long orgId, String fileName, String contentType,
byte[] content, String uploadedBy) {
requireOrg(orgId);
if (content == null || content.length == 0) {
throw new IllegalArgumentException("빈 파일은 올릴 수 없습니다.");
}
mapper.insertReport(orgId, fileName, contentType, content.length, content, uploadedBy);
return mapper.findReportsByOrg(orgId);
}
/**
* 올려둔 보고서를 새 파일로 바꾼다(요구사항 [25]). 목록에 새 줄이 생기지 않고 그 자리만
* 바뀐다 - 개정판으로 남기고 싶으면 새로 올리면 된다.
*/
@Transactional
public List replaceReport(Long orgId, Long reportId, String fileName,
String contentType, byte[] content, String uploadedBy) {
requireOrg(orgId);
if (content == null || content.length == 0) {
throw new IllegalArgumentException("빈 파일은 올릴 수 없습니다.");
}
int updated = mapper.updateReport(orgId, reportId, fileName, contentType, content.length,
content, uploadedBy);
if (updated == 0) {
throw new OrgNotFoundException("보고서를 찾을 수 없습니다: " + reportId);
}
return mapper.findReportsByOrg(orgId);
}
public ProjectMapper.ReportContent reportContent(Long orgId, Long reportId) {
requireOrg(orgId);
ProjectMapper.ReportContent content = mapper.findReportContent(orgId, reportId);
if (content == null) {
throw new OrgNotFoundException("보고서를 찾을 수 없습니다: " + reportId);
}
return content;
}
@Transactional
public void deleteReport(Long orgId, Long reportId) {
requireOrg(orgId);
if (mapper.deleteReport(orgId, reportId) == 0) {
throw new OrgNotFoundException("보고서를 찾을 수 없습니다: " + reportId);
}
}
private void requireOrg(Long orgId) {
if (orgMapper.findById(orgId) == null) {
throw new OrgNotFoundException("기관을 찾을 수 없습니다: " + orgId);
}
}
}