package com.kt.event.analytics.service;

import com.kt.event.analytics.dto.response.*;
import com.kt.event.analytics.entity.ChannelStats;
import com.kt.event.analytics.entity.EventStats;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.List;

/**
 * ROI 계산 유틸리티
 *
 * 이벤트의 투자 대비 수익률을 계산하는 비즈니스 로직
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ROICalculator {

    /**
     * ROI 상세 계산
     *
     * @param eventStats   이벤트 통계
     * @param channelStats 채널별 통계
     * @return ROI 상세 분석 결과
     */
    public RoiAnalyticsResponse calculateDetailedRoi(EventStats eventStats, List<ChannelStats> channelStats) {
        log.debug("ROI 상세 계산 시작: eventId={}", eventStats.getEventId());

        // 투자 비용 계산
        InvestmentDetails investment = calculateInvestment(eventStats, channelStats);

        // 수익 계산
        RevenueDetails revenue = calculateRevenue(eventStats);

        // ROI 계산
        RoiCalculation roiCalc = calculateRoi(investment, revenue);

        // 비용 효율성 계산
        CostEfficiency costEfficiency = calculateCostEfficiency(investment, revenue, eventStats);

        // 수익 예측
        RevenueProjection projection = projectRevenue(revenue, eventStats);

        return RoiAnalyticsResponse.builder()
            .eventId(eventStats.getEventId())
            .investment(investment)
            .revenue(revenue)
            .roi(roiCalc)
            .costEfficiency(costEfficiency)
            .projection(projection)
            .lastUpdatedAt(LocalDateTime.now())
            .build();
    }

    /**
     * 투자 비용 계산
     */
    private InvestmentDetails calculateInvestment(EventStats eventStats, List<ChannelStats> channelStats) {
        BigDecimal distributionCost = channelStats.stream()
            .map(ChannelStats::getDistributionCost)
            .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal contentCreation = eventStats.getTotalInvestment()
            .multiply(BigDecimal.valueOf(0.4)); // 전체 투자의 40%를 콘텐츠 제작비로 가정

        BigDecimal operation = eventStats.getTotalInvestment()
            .multiply(BigDecimal.valueOf(0.1)); // 10%를 운영비로 가정

        return InvestmentDetails.builder()
            .contentCreation(contentCreation)
            .distribution(distributionCost)
            .operation(operation)
            .total(eventStats.getTotalInvestment())
            .build();
    }

    /**
     * 수익 계산
     */
    private RevenueDetails calculateRevenue(EventStats eventStats) {
        BigDecimal directSales = eventStats.getExpectedRevenue()
            .multiply(BigDecimal.valueOf(0.66)); // 예상 수익의 66%를 직접 매출로 가정

        BigDecimal expectedSales = eventStats.getExpectedRevenue()
            .multiply(BigDecimal.valueOf(0.34)); // 34%를 예상 추가 매출로 가정

        BigDecimal brandValue = BigDecimal.ZERO; // 브랜드 가치는 별도 계산 필요

        return RevenueDetails.builder()
            .directSales(directSales)
            .expectedSales(expectedSales)
            .brandValue(brandValue)
            .total(eventStats.getExpectedRevenue())
            .build();
    }

    /**
     * ROI 계산
     */
    private RoiCalculation calculateRoi(InvestmentDetails investment, RevenueDetails revenue) {
        BigDecimal netProfit = revenue.getTotal().subtract(investment.getTotal());

        double roiPercentage = 0.0;
        if (investment.getTotal().compareTo(BigDecimal.ZERO) > 0) {
            roiPercentage = netProfit.divide(investment.getTotal(), 4, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(100))
                .doubleValue();
        }

        // 손익분기점 계산 (간단한 선형 모델)
        LocalDateTime breakEvenPoint = null;
        if (roiPercentage > 0) {
            breakEvenPoint = LocalDateTime.now().minusDays(5); // 예시
        }

        Integer paybackPeriod = roiPercentage > 0 ? 10 : null; // 예시

        return RoiCalculation.builder()
            .netProfit(netProfit)
            .roiPercentage(roiPercentage)
            .breakEvenPoint(breakEvenPoint)
            .paybackPeriod(paybackPeriod)
            .build();
    }

    /**
     * 비용 효율성 계산
     */
    private CostEfficiency calculateCostEfficiency(InvestmentDetails investment, RevenueDetails revenue, EventStats eventStats) {
        double costPerParticipant = 0.0;
        double costPerConversion = 0.0;
        double costPerView = 0.0;
        double revenuePerParticipant = 0.0;

        if (eventStats.getTotalParticipants() > 0) {
            costPerParticipant = investment.getTotal()
                .divide(BigDecimal.valueOf(eventStats.getTotalParticipants()), 2, RoundingMode.HALF_UP)
                .doubleValue();

            revenuePerParticipant = revenue.getTotal()
                .divide(BigDecimal.valueOf(eventStats.getTotalParticipants()), 2, RoundingMode.HALF_UP)
                .doubleValue();
        }

        return CostEfficiency.builder()
            .costPerParticipant(costPerParticipant)
            .costPerConversion(costPerConversion)
            .costPerView(costPerView)
            .revenuePerParticipant(revenuePerParticipant)
            .build();
    }

    /**
     * 수익 예측
     */
    private RevenueProjection projectRevenue(RevenueDetails revenue, EventStats eventStats) {
        BigDecimal projectedFinal = revenue.getTotal()
            .multiply(BigDecimal.valueOf(1.1)); // 현재 수익의 110%로 예측

        return RevenueProjection.builder()
            .currentRevenue(revenue.getTotal())
            .projectedFinalRevenue(projectedFinal)
            .confidenceLevel(85.5)
            .basedOn("현재 추세 및 과거 유사 이벤트 데이터")
            .build();
    }

    /**
     * ROI 요약 계산
     */
    public RoiSummary calculateRoiSummary(EventStats eventStats) {
        BigDecimal netProfit = eventStats.getExpectedRevenue().subtract(eventStats.getTotalInvestment());

        double roi = 0.0;
        if (eventStats.getTotalInvestment().compareTo(BigDecimal.ZERO) > 0) {
            roi = netProfit.divide(eventStats.getTotalInvestment(), 4, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(100))
                .doubleValue();
        }

        double cpa = 0.0;
        if (eventStats.getTotalParticipants() > 0) {
            cpa = eventStats.getTotalInvestment()
                .divide(BigDecimal.valueOf(eventStats.getTotalParticipants()), 2, RoundingMode.HALF_UP)
                .doubleValue();
        }

        return RoiSummary.builder()
            .totalCost(eventStats.getTotalInvestment())
            .expectedRevenue(eventStats.getExpectedRevenue())
            .netProfit(netProfit)
            .roi(roi)
            .costPerAcquisition(cpa)
            .build();
    }
}
