package com.honey.honey.repository;

import com.honey.honey.dto.ReferralProjection;
import com.honey.honey.model.UserD;
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.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

@Repository
public interface UserDRepository extends JpaRepository<UserD, Integer> {

    /**
     * Earliest {@code date_reg} on {@code db_users_d} (registration time), ignoring unset rows.
     */
    @Query("SELECT MIN(d.dateReg) FROM UserD d WHERE d.dateReg > 0")
    Optional<Integer> findMinDateReg();

    /**
     * Increments referals_1 for a user.
     */
    @Modifying
    @Query("UPDATE UserD u SET u.referals1 = u.referals1 + 1 WHERE u.id = :userId")
    void incrementReferals1(@Param("userId") Integer userId);
    
    /**
     * Increments referals_2 for a user.
     */
    @Modifying
    @Query("UPDATE UserD u SET u.referals2 = u.referals2 + 1 WHERE u.id = :userId")
    void incrementReferals2(@Param("userId") Integer userId);
    
    /**
     * Increments referals_3 for a user.
     */
    @Modifying
    @Query("UPDATE UserD u SET u.referals3 = u.referals3 + 1 WHERE u.id = :userId")
    void incrementReferals3(@Param("userId") Integer userId);
    
    /**
     * Increments referals_4 for a user.
     */
    @Modifying
    @Query("UPDATE UserD u SET u.referals4 = u.referals4 + 1 WHERE u.id = :userId")
    void incrementReferals4(@Param("userId") Integer userId);
    
    /**
     * Increments referals_5 for a user.
     */
    @Modifying
    @Query("UPDATE UserD u SET u.referals5 = u.referals5 + 1 WHERE u.id = :userId")
    void incrementReferals5(@Param("userId") Integer userId);
    
    /**
     * Finds referrals for level 1 (where referer_id_1 = userId).
     * Returns raw rows (name, commission bigint). Map to ReferralDto in service.
     */
    @Query("SELECT ud.screenName as name, ud.toReferer1 as commission " +
           "FROM UserD ud " +
           "WHERE ud.refererId1 = :userId AND ud.refererId1 > 0 " +
           "ORDER BY ud.toReferer1 DESC, ud.id DESC")
    Page<ReferralProjection> findReferralsLevel1(@Param("userId") Integer userId, Pageable pageable);

    /**
     * Finds referrals for level 2 (where referer_id_2 = userId).
     * Returns raw rows (name, commission bigint). Map to ReferralDto in service.
     */
    @Query("SELECT ud.screenName as name, ud.toReferer2 as commission " +
           "FROM UserD ud " +
           "WHERE ud.refererId2 = :userId AND ud.refererId2 > 0 " +
           "ORDER BY ud.toReferer2 DESC, ud.id DESC")
    Page<ReferralProjection> findReferralsLevel2(@Param("userId") Integer userId, Pageable pageable);

    /**
     * Finds referrals for level 3 (where referer_id_3 = userId).
     * Returns raw rows (name, commission bigint). Map to ReferralDto in service.
     */
    @Query("SELECT ud.screenName as name, ud.toReferer3 as commission " +
           "FROM UserD ud " +
           "WHERE ud.refererId3 = :userId AND ud.refererId3 > 0 " +
           "ORDER BY ud.toReferer3 DESC, ud.id DESC")
    Page<ReferralProjection> findReferralsLevel3(@Param("userId") Integer userId, Pageable pageable);

    /**
     * Masters: users whose id equals their master_id (and master_id > 0).
     * Ordered by id DESC (primary key) by default.
     */
    @Query("SELECT d FROM UserD d WHERE d.id = d.masterId AND d.masterId > 0 ORDER BY d.id DESC")
    List<UserD> findAllMasters();

    /**
     * IDs of users who are Masters (id = master_id and master_id > 0).
     */
    @Query("SELECT d.id FROM UserD d WHERE d.id = d.masterId AND d.masterId > 0")
    List<Integer> findMasterUserIds();

    /**
     * For each master_id in the list, returns total referral count (users with that master_id).
     * Returns Object[] { masterId (Integer), count (Long) }.
     */
    @Query(value = "SELECT d.master_id, COUNT(*) FROM db_users_d d WHERE d.master_id IN :masterIds GROUP BY d.master_id", nativeQuery = true)
    List<Object[]> countReferralsByMasterIds(@Param("masterIds") List<Integer> masterIds);

    /**
     * Sum of deposit_total and withdraw_total per master_id (over all users with that master_id).
     * Returns Object[] { masterId (Integer), sumDeposit (Long), sumWithdraw (Long) }.
     */
    @Query(value = "SELECT d.master_id, COALESCE(SUM(b.deposit_total),0), COALESCE(SUM(b.withdraw_total),0) FROM db_users_d d LEFT JOIN db_users_b b ON b.id = d.id WHERE d.master_id IN :masterIds GROUP BY d.master_id", nativeQuery = true)
    List<Object[]> sumDepositWithdrawByMasterIds(@Param("masterIds") List<Integer> masterIds);
}


