package com.zioinfo.kintex.work.report;

import com.zioinfo.kintex.auth.KintexPrincipal;
import com.zioinfo.kintex.common.PageResponse;
import com.zioinfo.kintex.common.error.ApiException;
import com.zioinfo.kintex.common.error.ErrorCode;
import com.zioinfo.kintex.system.SystemAccessGuard;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/** 보고서 서비스. 일반 사용자는 본인 보고서, 매니저/관리자는 전체 열람. 편집은 작성자 본인. */
@Service
public class ReportService {

    private final ReportMapper mapper;
    private final SystemAccessGuard scope;

    public ReportService(ReportMapper mapper, SystemAccessGuard scope) {
        this.mapper = mapper;
        this.scope = scope;
    }

    public PageResponse<ReportDto> list(KintexPrincipal principal, String eventId, String reportType,
                                        int page, int size) {
        int p = Math.max(page, 0);
        int s = size <= 0 ? 20 : Math.min(size, 200);
        Map<String, Object> q = new HashMap<>();
        q.put("mineOnly", !scope.canSeeAll(principal));
        q.put("userId", principal.userId());
        q.put("eventId", eventId);
        q.put("reportType", reportType);
        q.put("size", s);
        q.put("offset", p * s);
        List<Map<String, Object>> rows = mapper.search(q);
        long total = mapper.count(q);
        return PageResponse.of(rows.stream().map(ReportService::toDto).toList(), p, s, total);
    }

    public ReportDto get(KintexPrincipal principal, String id) {
        Map<String, Object> r = mapper.findById(id);
        if (r == null) {
            throw new ApiException(ErrorCode.NOT_FOUND);
        }
        if (!scope.canSeeAll(principal) && !principal.userId().equals(str(r.get("authorId")))) {
            throw new ApiException(ErrorCode.FORBIDDEN);
        }
        return toDto(r);
    }

    @Transactional
    public ReportDto create(KintexPrincipal principal, ReportSaveRequest req) {
        String id = "rp-" + UUID.randomUUID().toString().substring(0, 12);
        Map<String, Object> p = base(req);
        p.put("id", id);
        p.put("authorId", principal.userId());
        p.put("authorName", principal.displayName());
        mapper.insert(p);
        return get(principal, id);
    }

    @Transactional
    public ReportDto update(KintexPrincipal principal, String id, ReportSaveRequest req) {
        Map<String, Object> p = base(req);
        p.put("id", id);
        p.put("authorId", principal.userId());
        if (mapper.update(p) == 0) {
            throw new ApiException(ErrorCode.FORBIDDEN, "본인 보고서만 수정할 수 있습니다.");
        }
        return get(principal, id);
    }

    @Transactional
    public void delete(KintexPrincipal principal, String id) {
        if (mapper.delete(id, principal.userId()) == 0) {
            throw new ApiException(ErrorCode.FORBIDDEN, "본인 보고서만 삭제할 수 있습니다.");
        }
    }

    private static Map<String, Object> base(ReportSaveRequest req) {
        Map<String, Object> p = new HashMap<>();
        p.put("eventId", req.eventId());
        p.put("reportType", req.reportType());
        p.put("periodFrom", req.periodFrom());
        p.put("periodTo", req.periodTo());
        p.put("title", req.title());
        p.put("content", req.content());
        return p;
    }

    private static ReportDto toDto(Map<String, Object> r) {
        return new ReportDto(str(r.get("id")), str(r.get("eventId")), str(r.get("reportType")),
                str(r.get("periodFrom")), str(r.get("periodTo")), str(r.get("title")),
                str(r.get("content")), str(r.get("authorId")), str(r.get("authorName")), str(r.get("createdAt")));
    }
    private static String str(Object o) { return o == null ? null : String.valueOf(o); }
}
