package com.ga.api.service.kpi;

import com.ga.common.exception.BizException;
import com.ga.common.exception.ErrorCode;
import com.ga.common.model.PageResponse;
import com.ga.common.util.SecurityUtil;
import com.ga.core.mapper.kpi.RetentionAnomalyAlertMapper;
import com.ga.core.vo.kpi.RetentionAnomalyAlertResp;
import com.ga.core.vo.kpi.RetentionAnomalyAlertSaveReq;
import com.ga.core.vo.kpi.RetentionAnomalyAlertSearchParam;
import com.ga.core.vo.kpi.RetentionAnomalyAlertVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Set;

@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class RetentionAnomalyAlertService {

    private static final Set<String> VALID_STATUS = Set.of("NEW", "REVIEWED", "RESOLVED");

    private final RetentionAnomalyAlertMapper mapper;

    public PageResponse<RetentionAnomalyAlertResp> list(RetentionAnomalyAlertSearchParam param) {
        param.startPage();
        return PageResponse.of(mapper.selectList(param));
    }

    public RetentionAnomalyAlertResp detail(Long alertId) {
        RetentionAnomalyAlertResp resp = mapper.selectDetailById(alertId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        return resp;
    }

    /**
     * 이상치 탐지 — alertMonth 기준 직전 3개월 평균 대비 1.5%P 이상 편차를 탐지하고 저장.
     * @return 저장된 (또는 무시된) 알림 수
     */
    @Transactional
    public int detect(String alertMonth) {
        if (alertMonth == null || alertMonth.isBlank()) {
            throw new BizException(ErrorCode.INVALID_PARAMETER);
        }
        List<RetentionAnomalyAlertVO> found = mapper.detectAnomalies(alertMonth);
        if (found.isEmpty()) {
            log.info("[RetentionAnomaly] no anomalies for month={}", alertMonth);
            return 0;
        }
        int n = mapper.insertBatch(found);
        log.info("[RetentionAnomaly] detected={} inserted={}", found.size(), n);
        return n;
    }

    @Transactional
    public void review(RetentionAnomalyAlertSaveReq req) {
        if (req.getIds() == null || req.getIds().isEmpty()) {
            throw new BizException(ErrorCode.INVALID_PARAMETER);
        }
        String status = req.getStatus() == null ? "REVIEWED" : req.getStatus();
        if (!VALID_STATUS.contains(status)) {
            throw new BizException(ErrorCode.INVALID_PARAMETER);
        }
        mapper.updateStatus(req.getIds(), status, req.getNote(), SecurityUtil.getCurrentUserId());
    }
}
