package org.dromara.ai.monitor;

import lombok.Data;
import lombok.EqualsAndHashCode;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

/**
 * 用户AI使用监控指标
 * 继承基础监控指标，添加用户特有的监控数据
 *
 * @author pengles
 * @date 2024-01-01
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class UserMetrics extends BaseMetrics {

    /**
     * 用户ID
     */
    private Long userId;

    /**
     * 用户名
     */
    private String username;

    /**
     * 用户类型
     */
    private String userType;

    /**
     * 总消费金额（分）
     */
    private LongAdder totalSpent = new LongAdder();

    /**
     * 配额限制（分）
     */
    private long quotaLimit = 0;

    /**
     * 已使用配额（分）
     */
    private LongAdder usedQuota = new LongAdder();

    /**
     * 按模型分组的使用统计
     */
    private Map<String, AtomicLong> modelUsage = new ConcurrentHashMap<>();

    /**
     * 按Provider分组的使用统计
     */
    private Map<String, AtomicLong> providerUsage = new ConcurrentHashMap<>();

    /**
     * 会话数量
     */
    private AtomicLong sessionCount = new AtomicLong(0);

    /**
     * 平均会话长度（消息数）
     */
    private double avgSessionLength = 0.0;

    /**
     * 总会话长度
     */
    private LongAdder totalSessionLength = new LongAdder();

    /**
     * 最长会话长度
     */
    private AtomicLong maxSessionLength = new AtomicLong(0);

    /**
     * 首次使用时间
     */
    private LocalDateTime firstUsedTime;

    /**
     * 最后使用时间
     */
    private LocalDateTime lastUsedTime;

    /**
     * 最后登录时间
     */
    private LocalDateTime lastLoginTime;

    /**
     * 活跃天数
     */
    private AtomicLong activeDays = new AtomicLong(0);

    /**
     * 用户等级
     */
    private String userLevel = "BASIC";

    /**
     * 用户状态
     */
    private String status = "ACTIVE";

    /**
     * 违规次数
     */
    private AtomicLong violationCount = new AtomicLong(0);

    /**
     * 最后违规时间
     */
    private LocalDateTime lastViolationTime;

    public UserMetrics(Long userId, String username, String userType) {
        this.userId = userId;
        this.username = username;
        this.userType = userType;
        this.firstUsedTime = LocalDateTime.now();
        this.lastUsedTime = LocalDateTime.now();
        this.lastLoginTime = LocalDateTime.now();
    }

    /**
     * 记录消费
     *
     * @param amount 消费金额（分）
     */
    public void recordSpending(long amount) {
        totalSpent.add(amount);
        usedQuota.add(amount);
        lastUpdateTime = LocalDateTime.now();
    }

    /**
     * 记录模型使用
     *
     * @param modelId 模型ID
     */
    public void recordModelUsage(String modelId) {
        if (modelId != null && !modelId.isEmpty()) {
            modelUsage.computeIfAbsent(modelId, k -> new AtomicLong(0)).incrementAndGet();
            recordUsage();
        }
    }

    /**
     * 记录Provider使用
     *
     * @param providerName Provider名称
     */
    public void recordProviderUsage(String providerName) {
        if (providerName != null && !providerName.isEmpty()) {
            providerUsage.computeIfAbsent(providerName, k -> new AtomicLong(0)).incrementAndGet();
        }
    }

    /**
     * 开始新会话
     */
    public void startNewSession() {
        sessionCount.incrementAndGet();
        recordUsage();
    }

    /**
     * 结束会话
     *
     * @param messageCount 会话中的消息数量
     */
    public void endSession(int messageCount) {
        totalSessionLength.add(messageCount);

        // 更新最长会话长度
        long currentMax = maxSessionLength.get();
        while (messageCount > currentMax && !maxSessionLength.compareAndSet(currentMax, messageCount)) {
            currentMax = maxSessionLength.get();
        }

        updateAvgSessionLength();
        lastUpdateTime = LocalDateTime.now();
    }

    /**
     * 记录用户使用
     */
    public void recordUsage() {
        incrementTotalRequests();
        lastUsedTime = LocalDateTime.now();
        updateUserLevel();
    }

    /**
     * 记录登录
     */
    public void recordLogin() {
        lastLoginTime = LocalDateTime.now();
        // 简单的活跃天数计算逻辑
        activeDays.incrementAndGet();
    }

    /**
     * 记录违规
     *
     * @param violationType 违规类型
     */
    public void recordViolation(String violationType) {
        violationCount.incrementAndGet();
        lastViolationTime = LocalDateTime.now();
        incrementErrorCount(violationType);

        // 根据违规次数更新用户状态
        if (violationCount.get() >= 10) {
            status = "SUSPENDED";
        } else if (violationCount.get() >= 5) {
            status = "WARNING";
        }

        lastUpdateTime = LocalDateTime.now();
    }

    /**
     * 设置配额限制
     *
     * @param quotaLimit 配额限制（分）
     */
    public void setQuotaLimit(long quotaLimit) {
        this.quotaLimit = quotaLimit;
    }

    /**
     * 重置配额使用
     */
    public void resetQuota() {
        usedQuota.reset();
        lastUpdateTime = LocalDateTime.now();
    }

    /**
     * 检查是否超出配额
     */
    public boolean isQuotaExceeded() {
        return quotaLimit > 0 && usedQuota.longValue() >= quotaLimit;
    }

    /**
     * 获取剩余配额
     */
    public long getRemainingQuota() {
        if (quotaLimit <= 0) {
            return Long.MAX_VALUE; // 无限制
        }
        return Math.max(0, quotaLimit - usedQuota.longValue());
    }

    /**
     * 获取配额使用率
     */
    public double getQuotaUsageRate() {
        if (quotaLimit <= 0) {
            return 0.0;
        }
        return (double) usedQuota.longValue() / quotaLimit * 100;
    }

    /**
     * 获取最常用的模型
     */
    public String getMostUsedModel() {
        return modelUsage.entrySet().stream()
                .max(Map.Entry.comparingByValue((a, b) -> Long.compare(a.get(), b.get())))
                .map(Map.Entry::getKey)
                .orElse(null);
    }

    /**
     * 获取最常用的Provider
     */
    public String getMostUsedProvider() {
        return providerUsage.entrySet().stream()
                .max(Map.Entry.comparingByValue((a, b) -> Long.compare(a.get(), b.get())))
                .map(Map.Entry::getKey)
                .orElse(null);
    }

    /**
     * 获取用户活跃度评分 (0-100)
     */
    public double getActivityScore() {
        long totalReqs = getTotalRequests();
        long days = activeDays.get();
        long sessions = sessionCount.get();

        if (totalReqs == 0) {
            return 0.0;
        }

        // 基于请求数、活跃天数和会话数计算活跃度
        double requestScore = Math.min(50, Math.log10(totalReqs + 1) * 10);
        double dayScore = Math.min(30, days * 2);
        double sessionScore = Math.min(20, sessions * 0.5);

        return requestScore + dayScore + sessionScore;
    }

    /**
     * 更新平均会话长度
     */
    private void updateAvgSessionLength() {
        long sessions = sessionCount.get();
        if (sessions > 0) {
            avgSessionLength = totalSessionLength.doubleValue() / sessions;
        }
    }

    /**
     * 更新用户等级
     */
    private void updateUserLevel() {
        long totalReqs = getTotalRequests();
        long spent = totalSpent.longValue();

        if (totalReqs >= 10000 || spent >= 100000) { // 1000元
            userLevel = "PREMIUM";
        } else if (totalReqs >= 1000 || spent >= 10000) { // 100元
            userLevel = "ADVANCED";
        } else if (totalReqs >= 100 || spent >= 1000) { // 10元
            userLevel = "INTERMEDIATE";
        } else {
            userLevel = "BASIC";
        }
    }

    /**
     * 获取用户统计摘要
     */
    public String getUserSummary() {
        return String.format("User: %s, Level: %s, Requests: %d, Sessions: %d, Spent: %.2f, Status: %s",
                username, userLevel, getTotalRequests(), sessionCount.get(),
                totalSpent.doubleValue() / 100.0, status);
    }

    /**
     * 重置指标
     */
    @Override
    public void reset() {
        super.reset();
        totalSpent.reset();
        usedQuota.reset();
        modelUsage.clear();
        providerUsage.clear();
        sessionCount.set(0);
        totalSessionLength.reset();
        maxSessionLength.set(0);
        activeDays.set(0);
        violationCount.set(0);
        avgSessionLength = 0.0;
        userLevel = "BASIC";
        status = "ACTIVE";
        firstUsedTime = LocalDateTime.now();
        lastUsedTime = LocalDateTime.now();
        lastLoginTime = LocalDateTime.now();
        lastViolationTime = null;
    }
}