package com.honey.honey.service;

import com.honey.honey.dto.AdminMasterDto;
import com.honey.honey.model.UserD;
import com.honey.honey.repository.UserDRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class AdminMasterService {

    private static final BigDecimal USD_DIVISOR = new BigDecimal("1000000000");

    private final UserDRepository userDRepository;

    @Transactional(readOnly = true)
    public List<AdminMasterDto> getMasters() {
        List<UserD> masters = userDRepository.findAllMasters();
        if (masters.isEmpty()) {
            return List.of();
        }
        List<Integer> masterIds = masters.stream().map(UserD::getId).collect(Collectors.toList());

        Map<Integer, Long> referralCountByMaster = mapFromCountQuery(userDRepository.countReferralsByMasterIds(masterIds));
        Map<Integer, long[]> depositWithdrawByMaster = mapFromSumQuery(userDRepository.sumDepositWithdrawByMasterIds(masterIds));

        return masters.stream()
                .map(m -> {
                    int id = m.getId();
                    long totalReferrals = Math.max(0L, referralCountByMaster.getOrDefault(id, 0L) - 1L); // exclude master themselves from count
                    long[] sums = depositWithdrawByMaster.getOrDefault(id, new long[]{0L, 0L});
                    long sumDeposit = sums[0];
                    long sumWithdraw = sums[1];
                    BigDecimal depositUsd = BigDecimal.valueOf(sumDeposit).divide(USD_DIVISOR, 4, RoundingMode.HALF_UP);
                    BigDecimal withdrawUsd = BigDecimal.valueOf(sumWithdraw).divide(USD_DIVISOR, 4, RoundingMode.HALF_UP);
                    BigDecimal profitUsd = depositUsd.subtract(withdrawUsd);

                    return AdminMasterDto.builder()
                            .id(id)
                            .screenName(m.getScreenName() != null ? m.getScreenName() : "-")
                            .referals1(m.getReferals1() != null ? m.getReferals1() : 0)
                            .referals2(m.getReferals2() != null ? m.getReferals2() : 0)
                            .referals3(m.getReferals3() != null ? m.getReferals3() : 0)
                            .totalReferrals(totalReferrals)
                            .depositTotalUsd(depositUsd)
                            .withdrawTotalUsd(withdrawUsd)
                            .profitUsd(profitUsd)
                            .build();
                })
                .collect(Collectors.toList());
    }

    private static Map<Integer, Long> mapFromCountQuery(List<Object[]> rows) {
        return rows.stream()
                .collect(Collectors.toMap(
                        row -> (Integer) row[0],
                        row -> row[1] instanceof Long ? (Long) row[1] : ((Number) row[1]).longValue()
                ));
    }

    private static Map<Integer, long[]> mapFromSumQuery(List<Object[]> rows) {
        return rows.stream()
                .collect(Collectors.toMap(
                        row -> (Integer) row[0],
                        row -> new long[]{
                                row[1] instanceof Long ? (Long) row[1] : ((Number) row[1]).longValue(),
                                row[2] instanceof Long ? (Long) row[2] : ((Number) row[2]).longValue()
                        }
                ));
    }
}
