package com.zioinfo.cms.workflow;

import com.zioinfo.cms.common.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * GUARDiA CMS 게시 워크플로우 v2 — 25개 엔드포인트.
 * draft → submitted → approved/rejected → published/unpublished → archived 상태 전이.
 * DB 연동은 인메모리 구조체로 폴백(실제 운영 시 WorkflowMapper로 교체).
 */
@Slf4j
@RestController
@RequestMapping("/api/cms/workflow/v2")
public class PublishingWorkflowController {

    // ─────────── 인메모리 저장소 (개발/데모용) ───────────
    private final Map<Long, Map<String, Object>> rules = new ConcurrentHashMap<>();
    private final Map<Long, List<Map<String, Object>>> contentHistory = new ConcurrentHashMap<>();
    private final Map<Long, Map<String, Object>> contentStatus = new ConcurrentHashMap<>();
    private final Map<Long, Map<String, Object>> scheduledPublish = new ConcurrentHashMap<>();
    private final Map<Long, List<String>> collaborators = new ConcurrentHashMap<>();
    private final AtomicLong idSeq = new AtomicLong(1);

    private long nextId() { return idSeq.getAndIncrement(); }
    private String now() { return LocalDateTime.now().toString(); }
    private Map<String, Object> status(Long id) {
        return contentStatus.computeIfAbsent(id, k -> {
            Map<String, Object> s = new LinkedHashMap<>();
            s.put("contentId", id); s.put("status", "draft");
            s.put("updatedAt", now()); return s;
        });
    }
    private void addHistory(Long contentId, String action, String actor, String note) {
        contentHistory.computeIfAbsent(contentId, k -> new ArrayList<>())
            .add(Map.of("action", action, "actor", actor, "note", note == null ? "" : note, "at", now()));
    }

    // ─────────────────────────────────────────────────────────────
    // 1. GET /rules — 워크플로우 규칙 목록
    // ─────────────────────────────────────────────────────────────
    @GetMapping("/rules")
    public ResponseEntity<?> listRules() {
        return ResponseEntity.ok(ApiResponse.ok(new ArrayList<>(rules.values())));
    }

    // ─────────────────────────────────────────────────────────────
    // 2. POST /rules — 워크플로우 규칙 생성
    // ─────────────────────────────────────────────────────────────
    @PostMapping("/rules")
    public ResponseEntity<?> createRule(@RequestBody Map<String, Object> body) {
        long id = nextId();
        Map<String, Object> rule = new LinkedHashMap<>(body);
        rule.put("id", id); rule.put("createdAt", now()); rule.put("active", true);
        rules.put(id, rule);
        return ResponseEntity.ok(ApiResponse.ok(rule));
    }

    // ─────────────────────────────────────────────────────────────
    // 3. PUT /rules/{id} — 규칙 수정
    // ─────────────────────────────────────────────────────────────
    @PutMapping("/rules/{id}")
    public ResponseEntity<?> updateRule(@PathVariable Long id, @RequestBody Map<String, Object> body) {
        Map<String, Object> rule = rules.get(id);
        if (rule == null) return ResponseEntity.ok(ApiResponse.fail("규칙을 찾을 수 없습니다: " + id));
        rule.putAll(body); rule.put("id", id); rule.put("updatedAt", now());
        return ResponseEntity.ok(ApiResponse.ok(rule));
    }

    // ─────────────────────────────────────────────────────────────
    // 4. DELETE /rules/{id} — 규칙 삭제
    // ─────────────────────────────────────────────────────────────
    @DeleteMapping("/rules/{id}")
    public ResponseEntity<?> deleteRule(@PathVariable Long id) {
        rules.remove(id);
        return ResponseEntity.ok(ApiResponse.ok(Map.of("deleted", true, "id", id)));
    }

    // ─────────────────────────────────────────────────────────────
    // 5. GET /content/{contentId}/status — 콘텐츠 워크플로우 상태
    // ─────────────────────────────────────────────────────────────
    @GetMapping("/content/{contentId}/status")
    public ResponseEntity<?> getStatus(@PathVariable Long contentId) {
        return ResponseEntity.ok(ApiResponse.ok(status(contentId)));
    }

    // ─────────────────────────────────────────────────────────────
    // 6. POST /content/{contentId}/submit — 검토 요청 제출
    // ─────────────────────────────────────────────────────────────
    @PostMapping("/content/{contentId}/submit")
    public ResponseEntity<?> submit(@PathVariable Long contentId, @RequestBody(required=false) Map<String, Object> body) {
        Map<String, Object> s = status(contentId);
        s.put("status", "pending_review"); s.put("submittedAt", now());
        String submitter = body != null ? str(body.get("submitter")) : "author";
        s.put("submitter", submitter);
        addHistory(contentId, "SUBMIT", submitter, "검토 요청 제출");
        return ResponseEntity.ok(ApiResponse.ok(s));
    }

    // ─────────────────────────────────────────────────────────────
    // 7. POST /content/{contentId}/approve — 승인
    // ─────────────────────────────────────────────────────────────
    @PostMapping("/content/{contentId}/approve")
    public ResponseEntity<?> approve(@PathVariable Long contentId, @RequestBody(required=false) Map<String, Object> body) {
        Map<String, Object> s = status(contentId);
        String prevStatus = str(s.get("status"));
        s.put("status", "approved"); s.put("approvedAt", now());
        String approver = body != null ? str(body.get("approver")) : "editor";
        String note = body != null ? str(body.get("note")) : "";
        s.put("approver", approver);
        addHistory(contentId, "APPROVE", approver, note);
        return ResponseEntity.ok(ApiResponse.ok(Map.of("contentId", contentId,
            "previousStatus", prevStatus, "currentStatus", "approved", "approver", approver)));
    }

    // ─────────────────────────────────────────────────────────────
    // 8. POST /content/{contentId}/reject — 반려
    // ─────────────────────────────────────────────────────────────
    @PostMapping("/content/{contentId}/reject")
    public ResponseEntity<?> reject(@PathVariable Long contentId, @RequestBody Map<String, Object> body) {
        Map<String, Object> s = status(contentId);
        s.put("status", "rejected"); s.put("rejectedAt", now());
        String reviewer = str(body.getOrDefault("reviewer", "editor"));
        String reason   = str(body.getOrDefault("reason", ""));
        s.put("rejectedBy", reviewer); s.put("reason", reason);
        addHistory(contentId, "REJECT", reviewer, reason);
        return ResponseEntity.ok(ApiResponse.ok(Map.of("contentId", contentId,
            "status", "rejected", "reason", reason, "reviewer", reviewer)));
    }

    // ─────────────────────────────────────────────────────────────
    // 9. POST /content/{contentId}/request-revision — 수정 요청
    // ─────────────────────────────────────────────────────────────
    @PostMapping("/content/{contentId}/request-revision")
    public ResponseEntity<?> requestRevision(@PathVariable Long contentId, @RequestBody Map<String, Object> body) {
        Map<String, Object> s = status(contentId);
        s.put("status", "revision_requested"); s.put("revisionRequestedAt", now());
        String reviewer = str(body.getOrDefault("reviewer", "editor"));
        String comments = str(body.getOrDefault("comments", ""));
        s.put("revisionComments", comments);
        addHistory(contentId, "REQUEST_REVISION", reviewer, comments);
        return ResponseEntity.ok(ApiResponse.ok(Map.of("contentId", contentId,
            "status", "revision_requested", "comments", comments)));
    }

    // ─────────────────────────────────────────────────────────────
    // 10. GET /content/{contentId}/history — 워크플로우 이력
    // ─────────────────────────────────────────────────────────────
    @GetMapping("/content/{contentId}/history")
    public ResponseEntity<?> getHistory(@PathVariable Long contentId) {
        List<Map<String, Object>> hist = contentHistory.getOrDefault(contentId, List.of());
        return ResponseEntity.ok(ApiResponse.ok(Map.of("contentId", contentId, "history", hist, "count", hist.size())));
    }

    // ─────────────────────────────────────────────────────────────
    // 11. GET /pending/review — 검토 대기 콘텐츠
    // ─────────────────────────────────────────────────────────────
    @GetMapping("/pending/review")
    public ResponseEntity<?> pendingReview() {
        List<Map<String, Object>> list = contentStatus.values().stream()
            .filter(s -> "pending_review".equals(s.get("status"))).toList();
        return ResponseEntity.ok(ApiResponse.ok(Map.of("items", list, "count", list.size())));
    }

    // ─────────────────────────────────────────────────────────────
    // 12. GET /pending/approval — 승인 대기 콘텐츠
    // ─────────────────────────────────────────────────────────────
    @GetMapping("/pending/approval")
    public ResponseEntity<?> pendingApproval() {
        List<Map<String, Object>> list = contentStatus.values().stream()
            .filter(s -> "pending_approval".equals(s.get("status"))).toList();
        return ResponseEntity.ok(ApiResponse.ok(Map.of("items", list, "count", list.size())));
    }

    // ─────────────────────────────────────────────────────────────
    // 13. GET /scheduled — 예약 게시 목록
    // ─────────────────────────────────────────────────────────────
    @GetMapping("/scheduled")
    public ResponseEntity<?> getScheduled() {
        return ResponseEntity.ok(ApiResponse.ok(Map.of("items", new ArrayList<>(scheduledPublish.values()),
            "count", scheduledPublish.size())));
    }

    // ─────────────────────────────────────────────────────────────
    // 14. POST /content/{contentId}/schedule — 게시 예약
    // ─────────────────────────────────────────────────────────────
    @PostMapping("/content/{contentId}/schedule")
    public ResponseEntity<?> schedule(@PathVariable Long contentId, @RequestBody Map<String, Object> body) {
        String publishAt = str(body.getOrDefault("publishAt", ""));
        String expireAt  = str(body.getOrDefault("expireAt", ""));
        Map<String, Object> sched = new LinkedHashMap<>();
        sched.put("contentId", contentId); sched.put("publishAt", publishAt);
        sched.put("expireAt", expireAt); sched.put("scheduledAt", now()); sched.put("status", "SCHEDULED");
        scheduledPublish.put(contentId, sched);
        status(contentId).put("status", "scheduled");
        addHistory(contentId, "SCHEDULE", str(body.get("actor")), "예약 게시: " + publishAt);
        return ResponseEntity.ok(ApiResponse.ok(sched));
    }

    // ─────────────────────────────────────────────────────────────
    // 15. DELETE /content/{contentId}/schedule — 예약 취소
    // ─────────────────────────────────────────────────────────────
    @DeleteMapping("/content/{contentId}/schedule")
    public ResponseEntity<?> cancelSchedule(@PathVariable Long contentId) {
        scheduledPublish.remove(contentId);
        status(contentId).put("status", "approved");
        addHistory(contentId, "CANCEL_SCHEDULE", "system", "예약 취소");
        return ResponseEntity.ok(ApiResponse.ok(Map.of("contentId", contentId, "cancelled", true)));
    }

    // ─────────────────────────────────────────────────────────────
    // 16. POST /content/{contentId}/publish-now — 즉시 게시
    // ─────────────────────────────────────────────────────────────
    @PostMapping("/content/{contentId}/publish-now")
    public ResponseEntity<?> publishNow(@PathVariable Long contentId,
                                        @RequestBody(required=false) Map<String, Object> body) {
        Map<String, Object> s = status(contentId);
        s.put("status", "published"); s.put("publishedAt", now());
        String actor = body != null ? str(body.get("actor")) : "editor";
        addHistory(contentId, "PUBLISH", actor, "즉시 게시");
        return ResponseEntity.ok(ApiResponse.ok(Map.of("contentId", contentId,
            "status", "published", "publishedAt", now())));
    }

    // ─────────────────────────────────────────────────────────────
    // 17. POST /content/{contentId}/unpublish — 게시 취소
    // ─────────────────────────────────────────────────────────────
    @PostMapping("/content/{contentId}/unpublish")
    public ResponseEntity<?> unpublish(@PathVariable Long contentId,
                                       @RequestBody(required=false) Map<String, Object> body) {
        Map<String, Object> s = status(contentId);
        s.put("status", "unpublished"); s.put("unpublishedAt", now());
        String actor  = body != null ? str(body.get("actor")) : "editor";
        String reason = body != null ? str(body.get("reason")) : "";
        addHistory(contentId, "UNPUBLISH", actor, reason);
        return ResponseEntity.ok(ApiResponse.ok(Map.of("contentId", contentId, "status", "unpublished", "reason", reason)));
    }

    // ─────────────────────────────────────────────────────────────
    // 18. POST /content/{contentId}/archive — 아카이브
    // ─────────────────────────────────────────────────────────────
    @PostMapping("/content/{contentId}/archive")
    public ResponseEntity<?> archive(@PathVariable Long contentId,
                                     @RequestBody(required=false) Map<String, Object> body) {
        Map<String, Object> s = status(contentId);
        s.put("status", "archived"); s.put("archivedAt", now());
        String actor = body != null ? str(body.get("actor")) : "editor";
        addHistory(contentId, "ARCHIVE", actor, "아카이브");
        return ResponseEntity.ok(ApiResponse.ok(Map.of("contentId", contentId, "status", "archived", "archivedAt", now())));
    }

    // ─────────────────────────────────────────────────────────────
    // 19. GET /expiring — 만료 예정 콘텐츠 목록
    // ─────────────────────────────────────────────────────────────
    @GetMapping("/expiring")
    public ResponseEntity<?> expiring(@RequestParam(defaultValue = "7") int withinDays) {
        // 실제 운영 시 DB 쿼리로 교체
        List<Map<String, Object>> list = scheduledPublish.values().stream()
            .filter(s -> s.get("expireAt") != null && !str(s.get("expireAt")).isBlank())
            .toList();
        return ResponseEntity.ok(ApiResponse.ok(Map.of("expiring", list, "withinDays", withinDays, "count", list.size())));
    }

    // ─────────────────────────────────────────────────────────────
    // 20. PUT /content/{contentId}/extend — 만료 기간 연장
    // ─────────────────────────────────────────────────────────────
    @PutMapping("/content/{contentId}/extend")
    public ResponseEntity<?> extend(@PathVariable Long contentId, @RequestBody Map<String, Object> body) {
        String newExpireAt = str(body.getOrDefault("expireAt", ""));
        Map<String, Object> sched = scheduledPublish.computeIfAbsent(contentId, k -> new LinkedHashMap<>());
        sched.put("expireAt", newExpireAt); sched.put("extendedAt", now());
        addHistory(contentId, "EXTEND", str(body.get("actor")), "만료 기간 연장: " + newExpireAt);
        return ResponseEntity.ok(ApiResponse.ok(Map.of("contentId", contentId, "newExpireAt", newExpireAt)));
    }

    // ─────────────────────────────────────────────────────────────
    // 21. GET /content/{contentId}/collaborators — 협업자 목록
    // ─────────────────────────────────────────────────────────────
    @GetMapping("/content/{contentId}/collaborators")
    public ResponseEntity<?> getCollaborators(@PathVariable Long contentId) {
        List<String> list = collaborators.getOrDefault(contentId, List.of());
        return ResponseEntity.ok(ApiResponse.ok(Map.of("contentId", contentId, "collaborators", list, "count", list.size())));
    }

    // ─────────────────────────────────────────────────────────────
    // 22. POST /content/{contentId}/collaborators — 협업자 추가
    // ─────────────────────────────────────────────────────────────
    @PostMapping("/content/{contentId}/collaborators")
    public ResponseEntity<?> addCollaborator(@PathVariable Long contentId, @RequestBody Map<String, Object> body) {
        String user = str(body.getOrDefault("username", ""));
        String role = str(body.getOrDefault("role", "reviewer"));
        List<String> list = collaborators.computeIfAbsent(contentId, k -> new ArrayList<>());
        if (!list.contains(user)) list.add(user);
        addHistory(contentId, "ADD_COLLABORATOR", "admin", user + " 추가 (" + role + ")");
        return ResponseEntity.ok(ApiResponse.ok(Map.of("contentId", contentId, "added", user, "role", role, "collaborators", list)));
    }

    // ─────────────────────────────────────────────────────────────
    // 23. GET /dashboard — 워크플로우 현황 대시보드
    // ─────────────────────────────────────────────────────────────
    @GetMapping("/dashboard")
    public ResponseEntity<?> dashboard() {
        Map<String, Long> counts = new LinkedHashMap<>();
        counts.put("draft", 0L); counts.put("pending_review", 0L); counts.put("approved", 0L);
        counts.put("published", 0L); counts.put("rejected", 0L); counts.put("archived", 0L);
        contentStatus.values().forEach(s -> {
            String st = str(s.get("status"));
            counts.merge(st, 1L, Long::sum);
        });
        return ResponseEntity.ok(ApiResponse.ok(Map.of(
            "statusCounts", counts, "scheduledCount", scheduledPublish.size(),
            "totalRules", rules.size(), "generatedAt", now())));
    }

    // ─────────────────────────────────────────────────────────────
    // 24. GET /stats — 워크플로우 통계 (승인 소요시간 등)
    // ─────────────────────────────────────────────────────────────
    @GetMapping("/stats")
    public ResponseEntity<?> stats() {
        int totalContent = contentStatus.size();
        long published = contentStatus.values().stream().filter(s -> "published".equals(s.get("status"))).count();
        long rejected  = contentStatus.values().stream().filter(s -> "rejected".equals(s.get("status"))).count();
        double approvalRate = totalContent == 0 ? 0 : published * 100.0 / totalContent;
        return ResponseEntity.ok(ApiResponse.ok(Map.of(
            "totalContent", totalContent, "publishedCount", published, "rejectedCount", rejected,
            "approvalRate", String.format("%.1f%%", approvalRate),
            "avgApprovalTimeHours", 2.4, // 실제 DB 통계로 교체 필요
            "scheduledCount", scheduledPublish.size(), "generatedAt", now())));
    }

    // ─────────────────────────────────────────────────────────────
    // 25. POST /bulk-publish — 일괄 게시
    // ─────────────────────────────────────────────────────────────
    @PostMapping("/bulk-publish")
    public ResponseEntity<?> bulkPublish(@RequestBody Map<String, Object> body) {
        @SuppressWarnings("unchecked")
        List<Object> ids = body.get("contentIds") instanceof List<?> l
            ? (List<Object>) l : List.of();
        String actor = str(body.getOrDefault("actor", "editor"));
        List<Long> published = new ArrayList<>();
        List<Long> failed    = new ArrayList<>();
        for (Object idObj : ids) {
            try {
                Long cid = Long.valueOf(String.valueOf(idObj));
                Map<String, Object> s = status(cid);
                s.put("status", "published"); s.put("publishedAt", now());
                addHistory(cid, "BULK_PUBLISH", actor, "일괄 게시");
                published.add(cid);
            } catch (Exception e) { log.warn("일괄 게시 실패: {}", idObj); }
        }
        return ResponseEntity.ok(ApiResponse.ok(Map.of(
            "published", published, "failed", failed,
            "publishedCount", published.size(), "actor", actor, "publishedAt", now())));
    }

    private String str(Object o) { return o == null ? "" : String.valueOf(o); }
}
