package com.zioinfo.kintex.webhook.automation;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * F052 리드 팔로업 EDM 자동 트리거 — hot 리드(score&gt;=80) 발생/재계산 시 팔로업 캠페인 초안(status=draft)을
 * 자동 생성한다. <b>발송은 하지 않는다</b>(초안만 — 기존 마케팅 화면에서 조회됨).
 *
 * <p>구현: {@code @Scheduled} 5분 주기 스윕. 아직 로그가 없는 hot 리드만 골라 리드 1건당 캠페인 초안 1건 생성.
 * 멱등 키 {@code edm_followup_log UNIQUE(event_id, lead_id)} 로 중복 생성을 차단한다(로그 예약이 성공한 경우에만
 * 캠페인 insert). 리드/캠페인 테이블은 각각 read/insert 만 사용(visitor/marketing 패키지 파일 미수정).
 */
@Service
public class LeadFollowupAutomation {

    private static final Logger log = LoggerFactory.getLogger(LeadFollowupAutomation.class);

    /** 한 스윕당 처리 상한(폭주 방지). */
    private static final int SWEEP_LIMIT = 200;

    private final FollowupMapper mapper;

    public LeadFollowupAutomation(FollowupMapper mapper) {
        this.mapper = mapper;
    }

    /** 5분 주기 스윕(기동 60초 후 최초 실행). */
    @Scheduled(initialDelay = 60_000, fixedDelay = 300_000)
    public void scheduledSweep() {
        try {
            int created = sweepOnce();
            if (created > 0) {
                log.info("F052 팔로업 EDM 초안 자동 생성 {}건", created);
            }
        } catch (Exception e) {
            // 스케줄러는 조용히 실패 흡수(다음 주기 재시도) — 상세는 로그만.
            log.warn("F052 팔로업 스윕 실패: {}", e.getClass().getSimpleName());
        }
    }

    /**
     * 1회 스윕 — 미처리 hot 리드마다 로그 예약 후(멱등) 성공분에 한해 캠페인 초안을 생성한다.
     * @return 이번 스윕에서 새로 생성한 캠페인 초안 수
     */
    @Transactional
    public int sweepOnce() {
        List<Map<String, Object>> leads = mapper.findUnprocessedHotLeads(SWEEP_LIMIT);
        if (leads == null || leads.isEmpty()) {
            return 0;
        }
        int created = 0;
        for (Map<String, Object> l : leads) {
            String eventId = str(l.get("eventId"));
            String leadId = str(l.get("leadId"));
            if (eventId == null || leadId == null) {
                continue;
            }
            int score = intVal(l.get("score"));
            String bodyDraft = str(l.get("bodyDraft"));
            String logId = "fl-" + UUID.randomUUID().toString().replace("-", "").substring(0, 16);
            // 멱등 예약 — 이미 처리된 리드면 0(다른 스윕/인스턴스와의 경합도 흡수).
            if (mapper.reserveFollowup(logId, eventId, leadId, score, bodyDraft) == 0) {
                continue;
            }
            String campaignId = "cp-fl-" + UUID.randomUUID().toString().replace("-", "").substring(0, 12);
            mapper.insertFollowupCampaign(campaignId, eventId, buildName(l),
                    "hot 리드 자동 팔로업 (score " + score + ")");
            mapper.linkCampaign(logId, campaignId);
            created++;
        }
        return created;
    }

    private static String buildName(Map<String, Object> lead) {
        String company = str(lead.get("company"));
        String product = str(lead.get("product"));
        StringBuilder sb = new StringBuilder("[팔로업] ");
        sb.append(company == null || company.isBlank() ? "핫 리드" : company);
        if (product != null && !product.isBlank()) {
            sb.append(" · ").append(product);
        }
        return sb.length() > 290 ? sb.substring(0, 290) : sb.toString();
    }

    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 Integer.parseInt(String.valueOf(o));
        } catch (NumberFormatException e) {
            return 0;
        }
    }
}
