package com.zioinfo.kintex.work.notice;

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

    private final NoticeMapper mapper;

    public NoticeService(NoticeMapper mapper) {
        this.mapper = mapper;
    }

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

    @Transactional
    public NoticeDto get(String id) {
        Map<String, Object> r = mapper.findById(id);
        if (r == null) {
            throw new ApiException(ErrorCode.NOT_FOUND);
        }
        mapper.incrementView(id);
        return toDto(r);
    }

    @Transactional
    public NoticeDto create(KintexPrincipal principal, NoticeSaveRequest req) {
        String id = "nt-" + 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);
        Map<String, Object> r = mapper.findById(id);
        return toDto(r);
    }

    @Transactional
    public NoticeDto update(String id, NoticeSaveRequest req) {
        Map<String, Object> p = base(req);
        p.put("id", id);
        if (mapper.update(p) == 0) {
            throw new ApiException(ErrorCode.NOT_FOUND);
        }
        return toDto(mapper.findById(id));
    }

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

    private static Map<String, Object> base(NoticeSaveRequest req) {
        Map<String, Object> p = new HashMap<>();
        p.put("eventId", req.eventId());
        p.put("category", req.category());
        p.put("title", req.title());
        p.put("content", req.content());
        p.put("pinned", req.pinned());
        return p;
    }

    private static NoticeDto toDto(Map<String, Object> r) {
        return new NoticeDto(str(r.get("id")), str(r.get("eventId")), str(r.get("category")),
                str(r.get("title")), str(r.get("content")), bool(r.get("pinned")),
                str(r.get("authorId")), str(r.get("authorName")), intVal(r.get("viewCount")),
                str(r.get("publishedAt")), str(r.get("createdAt")));
    }
    private static String str(Object o) { return o == null ? null : String.valueOf(o); }
    private static boolean bool(Object o) {
        if (o instanceof Boolean b) return b;
        return o != null && Boolean.parseBoolean(String.valueOf(o));
    }
    private static int intVal(Object o) {
        if (o instanceof Number n) return n.intValue();
        try { return o == null ? 0 : Integer.parseInt(String.valueOf(o)); }
        catch (NumberFormatException e) { return 0; }
    }
}
