package com.honey.honey.controller;

import com.honey.honey.model.Payment;
import com.honey.honey.model.Payout;
import com.honey.honey.repository.PaymentRepository;
import com.honey.honey.repository.PayoutRepository;
import com.honey.honey.repository.UserARepository;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api/admin/analytics")
@RequiredArgsConstructor
@PreAuthorize("hasRole('ADMIN')")
public class AdminAnalyticsController {

    private final UserARepository userARepository;
    private final PaymentRepository paymentRepository;
    private final PayoutRepository payoutRepository;

    /**
     * Get revenue and payout time series data for charts.
     * @param range Time range: 7d, 30d, 90d, 1y, all
     * @return Time series data with daily/weekly/monthly aggregation
     */
    @GetMapping("/revenue")
    public ResponseEntity<Map<String, Object>> getRevenueAnalytics(
            @RequestParam(defaultValue = "30d") String range) {
        
        Instant now = Instant.now();
        Instant startDate;
        String granularity;
        
        // Determine start date and granularity based on range
        switch (range.toLowerCase()) {
            case "7d":
                startDate = now.minus(7, ChronoUnit.DAYS);
                granularity = "daily";
                break;
            case "30d":
                startDate = now.minus(30, ChronoUnit.DAYS);
                granularity = "daily";
                break;
            case "90d":
                startDate = now.minus(90, ChronoUnit.DAYS);
                granularity = "daily";
                break;
            case "1y":
                startDate = now.minus(365, ChronoUnit.DAYS);
                granularity = "weekly";
                break;
            case "all":
                startDate = Instant.ofEpochSecond(0); // All time
                granularity = "monthly";
                break;
            default:
                startDate = now.minus(30, ChronoUnit.DAYS);
                granularity = "daily";
        }
        
        List<Map<String, Object>> dataPoints = new ArrayList<>();
        Instant current = startDate;
        
        while (current.isBefore(now)) {
            Instant periodEnd;
            if (granularity.equals("daily")) {
                periodEnd = current.plus(1, ChronoUnit.DAYS);
            } else if (granularity.equals("weekly")) {
                periodEnd = current.plus(7, ChronoUnit.DAYS);
            } else {
                periodEnd = current.plus(30, ChronoUnit.DAYS);
            }
            
            if (periodEnd.isAfter(now)) {
                periodEnd = now;
            }
            
            // CRYPTO only: revenue and payouts in USD for this period
            java.math.BigDecimal revenueUsd = paymentRepository.sumUsdAmountByStatusAndUsdAmountNotNullAndCreatedAtBetween(
                    Payment.PaymentStatus.COMPLETED, current, periodEnd).orElse(java.math.BigDecimal.ZERO);
            java.math.BigDecimal payoutsUsd = payoutRepository.sumUsdAmountByTypeCryptoAndStatusAndCreatedAtBetween(
                    Payout.PayoutStatus.COMPLETED, current, periodEnd).orElse(java.math.BigDecimal.ZERO);
            java.math.BigDecimal netRevenueUsd = revenueUsd.subtract(payoutsUsd);
            
            Map<String, Object> point = new HashMap<>();
            point.put("date", current.getEpochSecond());
            point.put("revenue", revenueUsd);
            point.put("payouts", payoutsUsd);
            point.put("netRevenue", netRevenueUsd);
            
            dataPoints.add(point);
            
            current = periodEnd;
        }
        
        Map<String, Object> response = new HashMap<>();
        response.put("range", range);
        response.put("granularity", granularity);
        response.put("data", dataPoints);
        
        return ResponseEntity.ok(response);
    }

    /**
     * Get user activity time series data (registrations, active players, rounds).
     * @param range Time range: 7d, 30d, 90d, 1y, all
     * @return Time series data
     */
    @GetMapping("/activity")
    public ResponseEntity<Map<String, Object>> getActivityAnalytics(
            @RequestParam(defaultValue = "30d") String range) {
        
        Instant now = Instant.now();
        Instant startDate;
        String granularity;
        
        switch (range.toLowerCase()) {
            case "7d":
                startDate = now.minus(7, ChronoUnit.DAYS);
                granularity = "daily";
                break;
            case "30d":
                startDate = now.minus(30, ChronoUnit.DAYS);
                granularity = "daily";
                break;
            case "90d":
                startDate = now.minus(90, ChronoUnit.DAYS);
                granularity = "daily";
                break;
            case "1y":
                startDate = now.minus(365, ChronoUnit.DAYS);
                granularity = "weekly";
                break;
            case "all":
                startDate = Instant.ofEpochSecond(0);
                granularity = "monthly";
                break;
            default:
                startDate = now.minus(30, ChronoUnit.DAYS);
                granularity = "daily";
        }
        
        List<Map<String, Object>> dataPoints = new ArrayList<>();
        Instant current = startDate;
        
        while (current.isBefore(now)) {
            Instant periodEnd;
            if (granularity.equals("daily")) {
                periodEnd = current.plus(1, ChronoUnit.DAYS);
            } else if (granularity.equals("weekly")) {
                periodEnd = current.plus(7, ChronoUnit.DAYS);
            } else {
                periodEnd = current.plus(30, ChronoUnit.DAYS);
            }
            
            if (periodEnd.isAfter(now)) {
                periodEnd = now;
            }
            
            // Convert to Unix timestamps for UserA queries
            int periodStartTs = (int) current.getEpochSecond();
            int periodEndTs = (int) periodEnd.getEpochSecond();
            
            // Count new registrations in this period (between current and periodEnd)
            long newUsers = userARepository.countByDateRegBetween(periodStartTs, periodEndTs);
            
            // Count active players (logged in) in this period
            long activePlayers = userARepository.countByDateLoginBetween(periodStartTs, periodEndTs);
            
            Map<String, Object> point = new HashMap<>();
            point.put("date", current.getEpochSecond());
            point.put("newUsers", newUsers);
            point.put("activePlayers", activePlayers);
            point.put("rounds", 0L);
            
            dataPoints.add(point);
            
            current = periodEnd;
        }
        
        Map<String, Object> response = new HashMap<>();
        response.put("range", range);
        response.put("granularity", granularity);
        response.put("data", dataPoints);
        
        return ResponseEntity.ok(response);
    }
}

