package com.zioinfo.kintex.work.meeting;

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

    private final MeetingMapper mapper;

    public MeetingService(MeetingMapper mapper) {
        this.mapper = mapper;
    }

    public PageResponse<MeetingDto> list(String eventId, 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("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(MeetingService::toDto).toList(), p, s, total);
    }

    public MeetingDetail get(String id) {
        Map<String, Object> r = mapper.findById(id);
        if (r == null) {
            throw new ApiException(ErrorCode.NOT_FOUND);
        }
        List<MeetingActionDto> actions = mapper.findActions(id).stream()
                .map(MeetingService::toAction).toList();
        return new MeetingDetail(toDto(r), actions);
    }

    @Transactional
    public MeetingDto create(KintexPrincipal principal, MeetingSaveRequest req) {
        String id = "mt-" + UUID.randomUUID().toString().substring(0, 12);
        Map<String, Object> p = base(req);
        p.put("id", id);
        p.put("organizerId", principal.userId());
        p.put("organizerName", principal.displayName());
        mapper.insert(p);
        return toDto(mapper.findById(id));
    }

    @Transactional
    public MeetingDto update(KintexPrincipal principal, String id, MeetingSaveRequest req) {
        Map<String, Object> p = base(req);
        p.put("id", id);
        p.put("organizerId", principal.userId());
        if (mapper.update(p) == 0) {
            throw new ApiException(ErrorCode.FORBIDDEN, "주최자만 회의를 수정할 수 있습니다.");
        }
        return toDto(mapper.findById(id));
    }

    @Transactional
    public void saveMinutes(String id, String minutes) {
        if (mapper.updateMinutes(id, minutes) == 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 MeetingActionDto addAction(String meetingId, MeetingActionRequest req) {
        if (mapper.findById(meetingId) == null) {
            throw new ApiException(ErrorCode.NOT_FOUND);
        }
        String id = "ma-" + UUID.randomUUID().toString().substring(0, 12);
        int seq = mapper.maxSeq(meetingId) + 1;
        Map<String, Object> p = new HashMap<>();
        p.put("id", id);
        p.put("meetingId", meetingId);
        p.put("seq", seq);
        p.put("actionItem", req.actionItem());
        p.put("assigneeId", req.assigneeId());
        p.put("dueDate", req.dueDate());
        mapper.insertAction(p);
        return mapper.findActions(meetingId).stream()
                .filter(a -> id.equals(String.valueOf(a.get("id"))))
                .map(MeetingService::toAction).findFirst().orElseThrow();
    }

    @Transactional
    public void updateActionStatus(String actionId, String status) {
        mapper.updateActionStatus(actionId, status);
    }

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

    private static MeetingDto toDto(Map<String, Object> r) {
        return new MeetingDto(str(r.get("id")), str(r.get("eventId")), str(r.get("title")),
                str(r.get("location")), str(r.get("meetingAt")), str(r.get("organizerId")),
                str(r.get("organizerName")), str(r.get("content")), str(r.get("minutes")),
                str(r.get("createdAt")));
    }
    private static MeetingActionDto toAction(Map<String, Object> r) {
        return new MeetingActionDto(str(r.get("id")), str(r.get("meetingId")), intVal(r.get("seq")),
                str(r.get("actionItem")), str(r.get("assigneeId")), str(r.get("dueDate")), str(r.get("status")));
    }
    private static String str(Object o) { return o == null ? null : 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; }
    }
}
