package com.pharmacopoeia.repository;

import com.pharmacopoeia.entity.UserEvent;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.time.Instant;
import java.util.List;

@Repository
public interface UserEventRepository extends JpaRepository<UserEvent, Long>,
        JpaSpecificationExecutor<UserEvent> {

    // systemSource 为 null 时不过滤（用于 system=all 跨系统统计）
    /** 总数 */
    @Query("SELECT COUNT(e) FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource)")
    long countTotal(@Param("startTime") Instant startTime, @Param("endTime") Instant endTime,
                    @Param("systemSource") String systemSource);

    /** 去重活跃用户数 */
    @Query("SELECT COUNT(DISTINCT e.userKey) FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource)")
    long countDistinctUsers(@Param("startTime") Instant startTime, @Param("endTime") Instant endTime,
                            @Param("systemSource") String systemSource);

    /** 去重 IP 数 */
    @Query("SELECT COUNT(DISTINCT e.ip) FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource)")
    long countDistinctIps(@Param("startTime") Instant startTime, @Param("endTime") Instant endTime,
                          @Param("systemSource") String systemSource);

    /** 按类型 count */
    @Query("SELECT COUNT(e) FROM UserEvent e " +
           "WHERE e.eventType = :eventType " +
           "AND e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource)")
    long countByType(@Param("eventType") String eventType,
                     @Param("startTime") Instant startTime, @Param("endTime") Instant endTime,
                     @Param("systemSource") String systemSource);

    // ==================== 分组统计（全量，供其他场景用） ====================

    @Query("SELECT e.ip as key, COUNT(e) as cnt FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource) " +
           "GROUP BY e.ip ORDER BY cnt DESC")
    List<Object[]> countByIp(@Param("startTime") Instant startTime, @Param("endTime") Instant endTime,
                             @Param("systemSource") String systemSource);

    @Query("SELECT e.pageUrl as key, COUNT(e) as cnt FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource) " +
           "GROUP BY e.pageUrl ORDER BY cnt DESC")
    List<Object[]> countByPageUrl(@Param("startTime") Instant startTime, @Param("endTime") Instant endTime,
                                  @Param("systemSource") String systemSource);

    @Query("SELECT e.eventType as key, COUNT(e) as cnt FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource) " +
           "GROUP BY e.eventType ORDER BY cnt DESC")
    List<Object[]> countByEventType(@Param("startTime") Instant startTime, @Param("endTime") Instant endTime,
                                    @Param("systemSource") String systemSource);

    @Query("SELECT e.userKey as key, COUNT(e) as cnt FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource) " +
           "GROUP BY e.userKey ORDER BY cnt DESC")
    List<Object[]> countByUserKey(@Param("startTime") Instant startTime, @Param("endTime") Instant endTime,
                                  @Param("systemSource") String systemSource);

    @Query("SELECT e.userKey, e.ip, COUNT(e) as cnt FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource) " +
           "GROUP BY e.userKey, e.ip ORDER BY e.userKey, cnt DESC")
    List<Object[]> countByUserIp(@Param("startTime") Instant startTime, @Param("endTime") Instant endTime,
                                 @Param("systemSource") String systemSource);

    // ==================== 分组统计（分页） ====================

    @Query(value = "SELECT e.ip as key, COUNT(e) as cnt FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource) " +
           "GROUP BY e.ip ORDER BY cnt DESC",
           countQuery = "SELECT COUNT(DISTINCT e.ip) FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource)")
    Page<Object[]> countByIpPaged(@Param("startTime") Instant startTime,
                                   @Param("endTime") Instant endTime,
                                   @Param("systemSource") String systemSource, Pageable pageable);

    @Query(value = "SELECT e.pageUrl as key, COUNT(e) as cnt FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource) " +
           "GROUP BY e.pageUrl ORDER BY cnt DESC",
           countQuery = "SELECT COUNT(DISTINCT e.pageUrl) FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource)")
    Page<Object[]> countByPageUrlPaged(@Param("startTime") Instant startTime,
                                        @Param("endTime") Instant endTime,
                                        @Param("systemSource") String systemSource, Pageable pageable);

    @Query(value = "SELECT e.eventType as key, COUNT(e) as cnt FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource) " +
           "GROUP BY e.eventType ORDER BY cnt DESC",
           countQuery = "SELECT COUNT(DISTINCT e.eventType) FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource)")
    Page<Object[]> countByEventTypePaged(@Param("startTime") Instant startTime,
                                          @Param("endTime") Instant endTime,
                                          @Param("systemSource") String systemSource, Pageable pageable);

    @Query(value = "SELECT e.userKey as key, COUNT(e) as cnt FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource) " +
           "GROUP BY e.userKey ORDER BY cnt DESC",
           countQuery = "SELECT COUNT(DISTINCT e.userKey) FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource)")
    Page<Object[]> countByUserKeyPaged(@Param("startTime") Instant startTime,
                                        @Param("endTime") Instant endTime,
                                        @Param("systemSource") String systemSource, Pageable pageable);

    @Query(value = "SELECT e.userKey, e.ip, COUNT(e) as cnt FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource) " +
           "GROUP BY e.userKey, e.ip ORDER BY e.userKey, cnt DESC",
           countQuery = "SELECT COUNT(*) FROM (" +
               "SELECT e2.userKey AS userKey, e2.ip AS ip FROM UserEvent e2 " +
               "WHERE e2.createdAt >= :startTime AND e2.createdAt < :endTime " +
               "AND (:systemSource IS NULL OR e2.systemSource = :systemSource) " +
               "GROUP BY e2.userKey, e2.ip) sub")
    Page<Object[]> countByUserIpPaged(@Param("startTime") Instant startTime,
                                       @Param("endTime") Instant endTime,
                                       @Param("systemSource") String systemSource, Pageable pageable);

    /** 获取所有去重事件类型，供前端筛选 */
    @Query("SELECT DISTINCT e.eventType FROM UserEvent e ORDER BY e.eventType")
    List<String> findDistinctEventTypes();

    /** 获取所有去重来源系统，供前端系统切换系统维度 */
    @Query("SELECT DISTINCT e.systemSource FROM UserEvent e " +
           "WHERE e.systemSource IS NOT NULL " +
           "ORDER BY e.systemSource")
    List<String> findDistinctSystemSources();

    // ==================== 导出（只取 6 列投影，避免加载 jsonb/UA 等大字段） ====================

    /** 导出前 count：与 findForExport 同条件，systemSource/eventType 为 null 时不过滤 */
    @Query("SELECT COUNT(e) FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource) " +
           "AND (:eventType IS NULL OR e.eventType = :eventType)")
    long countForExport(@Param("startTime") Instant startTime, @Param("endTime") Instant endTime,
                       @Param("systemSource") String systemSource, @Param("eventType") String eventType);

    /** 按筛选条件全量查询导出列，按时间倒序；id/system/eventType/userKey/ip/createdAt */
    @Query("SELECT e.id, e.systemSource, e.eventType, e.userKey, e.ip, e.createdAt FROM UserEvent e " +
           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime " +
           "AND (:systemSource IS NULL OR e.systemSource = :systemSource) " +
           "AND (:eventType IS NULL OR e.eventType = :eventType) " +
           "ORDER BY e.createdAt DESC")
    List<Object[]> findForExport(@Param("startTime") Instant startTime, @Param("endTime") Instant endTime,
                                @Param("systemSource") String systemSource, @Param("eventType") String eventType);
}
