package com.honey.honey.controller;

import com.honey.honey.dto.AdminPaymentDto;
import com.honey.honey.model.Payment;
import com.honey.honey.model.UserA;
import com.honey.honey.repository.PaymentRepository;
import com.honey.honey.repository.UserARepository;
import com.honey.honey.repository.UserDRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
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 jakarta.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/admin/payments")
@RequiredArgsConstructor
@PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')")
public class AdminPaymentController {

    private final PaymentRepository paymentRepository;
    private final UserARepository userARepository;
    private final UserDRepository userDRepository;

    private static boolean isSupport() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth == null || auth.getAuthorities() == null) return false;
        return auth.getAuthorities().stream()
                .anyMatch(a -> "ROLE_SUPPORT".equals(a.getAuthority()));
    }

    @GetMapping
    public ResponseEntity<Map<String, Object>> getPayments(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "50") int size,
            @RequestParam(required = false) String sortBy,
            @RequestParam(required = false) String sortDir,
            // Filters
            @RequestParam(required = false) String status,
            @RequestParam(required = false) Integer userId,
            @RequestParam(required = false) String dateFrom,
            @RequestParam(required = false) String dateTo,
            @RequestParam(required = false) Long amountMin,
            @RequestParam(required = false) Long amountMax) {

        // Build sort
        Sort sort = Sort.by("createdAt").descending(); // Default sort
        if (sortBy != null && !sortBy.trim().isEmpty()) {
            Sort.Direction direction = "asc".equalsIgnoreCase(sortDir)
                    ? Sort.Direction.ASC
                    : Sort.Direction.DESC;
            sort = Sort.by(direction, sortBy);
        }

        Pageable pageable = PageRequest.of(page, size, sort);

        List<Integer> masterIds = isSupport() ? userDRepository.findMasterUserIds() : List.of();

        // Build specification
        Specification<Payment> spec = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();

            if (!masterIds.isEmpty()) {
                predicates.add(cb.not(root.get("userId").in(masterIds)));
            }
            if (status != null && !status.trim().isEmpty()) {
                try {
                    Payment.PaymentStatus paymentStatus = Payment.PaymentStatus.valueOf(status.toUpperCase());
                    predicates.add(cb.equal(root.get("status"), paymentStatus));
                } catch (IllegalArgumentException e) {
                    // Invalid status, ignore
                }
            }

            if (userId != null) {
                predicates.add(cb.equal(root.get("userId"), userId));
            }

            // Date range filters would need Instant conversion
            // For now, we'll skip them or implement if needed

            return cb.and(predicates.toArray(new Predicate[0]));
        };

        Page<Payment> paymentPage = paymentRepository.findAll(spec, pageable);

        // Fetch user names
        List<Integer> userIds = paymentPage.getContent().stream()
                .map(Payment::getUserId)
                .distinct()
                .collect(Collectors.toList());

        Map<Integer, String> userNameMap = userARepository.findAllById(userIds).stream()
                .collect(Collectors.toMap(
                        UserA::getId,
                        u -> u.getTelegramName() != null && !u.getTelegramName().equals("-")
                                ? u.getTelegramName()
                                : u.getScreenName()
                ));

        // Convert to DTOs
        Page<AdminPaymentDto> dtoPage = paymentPage.map(payment -> {
            String userName = userNameMap.getOrDefault(payment.getUserId(), "Unknown");
            return AdminPaymentDto.builder()
                    .id(payment.getId())
                    .userId(payment.getUserId())
                    .userName(userName)
                    .orderId(payment.getOrderId())
                    .starsAmount(payment.getStarsAmount())
                    .ticketsAmount(payment.getTicketsAmount())
                    .usdAmount(payment.getUsdAmount())
                    .status(payment.getStatus().name())
                    .telegramPaymentChargeId(payment.getTelegramPaymentChargeId())
                    .telegramProviderPaymentChargeId(payment.getTelegramProviderPaymentChargeId())
                    .createdAt(payment.getCreatedAt())
                    .completedAt(payment.getCompletedAt())
                    .build();
        });

        Map<String, Object> response = new HashMap<>();
        response.put("content", dtoPage.getContent());
        response.put("totalElements", dtoPage.getTotalElements());
        response.put("totalPages", dtoPage.getTotalPages());
        response.put("currentPage", dtoPage.getNumber());
        response.put("size", dtoPage.getSize());
        response.put("hasNext", dtoPage.hasNext());
        response.put("hasPrevious", dtoPage.hasPrevious());

        return ResponseEntity.ok(response);
    }
}

