package com.zioinfo.kintex.work.opinion;

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 OpinionService {

    private final OpinionMapper mapper;
    private final SystemAccessGuard scope;

    public OpinionService(OpinionMapper mapper, SystemAccessGuard scope) {
        this.mapper = mapper;
        this.scope = scope;
    }

    public PageResponse<OpinionDto> list(String eventId, String status, 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("eventId", eventId);
        q.put("status", status);
        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(OpinionService::toDto).toList(), p, s, total);
    }

    public OpinionDetail get(KintexPrincipal principal, String id) {
        Map<String, Object> r = mapper.findById(id);
        if (r == null) {
            throw new ApiException(ErrorCode.NOT_FOUND);
        }
        boolean secret = "Y".equals(str(r.get("secretYn")));
        boolean owner = principal.userId().equals(str(r.get("authorId")));
        if (secret && !owner && !scope.canSeeAll(principal)) {
            throw new ApiException(ErrorCode.FORBIDDEN, "비밀 의견은 작성자와 담당자만 볼 수 있습니다.");
        }
        List<OpinionCommentDto> comments = mapper.findComments(id).stream()
                .map(OpinionService::toComment).toList();
        return new OpinionDetail(toDto(r), comments);
    }

    @Transactional
    public OpinionDto create(KintexPrincipal principal, OpinionSaveRequest req) {
        String id = "op-" + UUID.randomUUID().toString().substring(0, 12);
        Map<String, Object> p = new HashMap<>();
        p.put("id", id);
        p.put("eventId", req.eventId());
        p.put("category", req.category());
        p.put("title", req.title());
        p.put("content", req.content());
        p.put("secretYn", req.secretYn());
        p.put("authorId", principal.userId());
        p.put("authorName", principal.displayName());
        mapper.insert(p);
        return toDto(mapper.findById(id));
    }

    @Transactional
    public void changeStatus(String id, String status) {
        if (mapper.updateStatus(id, status) == 0) {
            throw new ApiException(ErrorCode.NOT_FOUND);
        }
    }

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

    @Transactional
    public OpinionCommentDto addComment(KintexPrincipal principal, String opinionId, String content) {
        if (mapper.findById(opinionId) == null) {
            throw new ApiException(ErrorCode.NOT_FOUND);
        }
        String id = "oc-" + UUID.randomUUID().toString().substring(0, 12);
        Map<String, Object> p = new HashMap<>();
        p.put("id", id);
        p.put("opinionId", opinionId);
        p.put("authorId", principal.userId());
        p.put("authorName", principal.displayName());
        p.put("content", content);
        mapper.insertComment(p);
        return mapper.findComments(opinionId).stream()
                .filter(c -> id.equals(String.valueOf(c.get("id"))))
                .map(OpinionService::toComment).findFirst().orElseThrow();
    }

    private static OpinionDto toDto(Map<String, Object> r) {
        return new OpinionDto(str(r.get("id")), str(r.get("eventId")), str(r.get("category")),
                str(r.get("title")), str(r.get("content")), str(r.get("status")),
                str(r.get("authorId")), str(r.get("authorName")), str(r.get("secretYn")),
                str(r.get("createdAt")));
    }
    private static OpinionCommentDto toComment(Map<String, Object> r) {
        return new OpinionCommentDto(str(r.get("id")), str(r.get("opinionId")), str(r.get("authorId")),
                str(r.get("authorName")), str(r.get("content")), str(r.get("createdAt")));
    }
    private static String str(Object o) { return o == null ? null : String.valueOf(o); }
}
