package com.honey.honey.controller;

import com.honey.honey.dto.AdminPayoutDto;
import com.honey.honey.model.Payout;
import com.honey.honey.model.UserA;
import com.honey.honey.model.UserB;
import com.honey.honey.repository.PayoutRepository;
import com.honey.honey.repository.UserARepository;
import com.honey.honey.repository.UserBRepository;
import com.honey.honey.repository.UserDRepository;
import com.honey.honey.service.LocalizationService;
import com.honey.honey.service.PayoutService;
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.*;

import jakarta.persistence.criteria.Predicate;
import org.springframework.http.HttpStatus;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

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

    private final PayoutRepository payoutRepository;
    private final UserARepository userARepository;
    private final UserBRepository userBRepository;
    private final UserDRepository userDRepository;
    private final PayoutService payoutService;
    private final LocalizationService localizationService;

    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>> getPayouts(
            @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 type) {

        // 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<Payout> 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 {
                    Payout.PayoutStatus payoutStatus = Payout.PayoutStatus.valueOf(status.toUpperCase());
                    predicates.add(cb.equal(root.get("status"), payoutStatus));
                } catch (IllegalArgumentException e) {
                    // Invalid status, ignore
                }
            }

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

            if (type != null && !type.trim().isEmpty()) {
                try {
                    Payout.PayoutType payoutType = Payout.PayoutType.valueOf(type.toUpperCase());
                    predicates.add(cb.equal(root.get("type"), payoutType));
                } catch (IllegalArgumentException e) {
                    // Invalid type, ignore
                }
            }

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

        Page<Payout> payoutPage = payoutRepository.findAll(spec, pageable);

        // Fetch user names
        List<Integer> userIds = payoutPage.getContent().stream()
                .map(Payout::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<AdminPayoutDto> dtoPage = payoutPage.map(payout -> {
            String userName = userNameMap.getOrDefault(payout.getUserId(), "Unknown");
            return AdminPayoutDto.builder()
                    .id(payout.getId())
                    .userId(payout.getUserId())
                    .userName(userName)
                    .username(payout.getUsername())
                    .type(payout.getType().name())
                    .giftName(payout.getGiftName() != null ? payout.getGiftName().name() : null)
                    .total(payout.getTotal())
                    .usdAmount(payout.getUsdAmount())
                    .starsAmount(payout.getStarsAmount())
                    .quantity(payout.getQuantity())
                    .status(payout.getStatus().name())
                    .createdAt(payout.getCreatedAt())
                    .resolvedAt(payout.getResolvedAt())
                    .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);
    }

    @PostMapping("/{id}/complete")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<?> completePayout(@PathVariable Long id) {
        try {
            Optional<Payout> payoutOpt = payoutRepository.findById(id);
            if (payoutOpt.isEmpty()) {
                return ResponseEntity.badRequest()
                        .body(Map.of("error", localizationService.getMessage("payout.error.notFound", String.valueOf(id))));
            }
            Payout payout = payoutOpt.get();
            if (payout.getStatus() != Payout.PayoutStatus.PROCESSING) {
                return ResponseEntity.badRequest()
                        .body(Map.of("error", localizationService.getMessage("payout.error.onlyProcessingCanComplete", payout.getStatus().name())));
            }
            payoutService.markPayoutCompleted(id);
            return ResponseEntity.ok(Map.of("message", "Payout marked as completed"));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().body(Map.of("error", e.getMessage()));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of("error", e.getMessage()));
        }
    }

    @PostMapping("/{id}/cancel")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<?> cancelPayout(@PathVariable Long id) {
        try {
            Optional<Payout> payoutOpt = payoutRepository.findById(id);
            if (payoutOpt.isEmpty()) {
                return ResponseEntity.badRequest()
                        .body(Map.of("error", localizationService.getMessage("payout.error.notFound", String.valueOf(id))));
            }
            Payout payout = payoutOpt.get();
            if (payout.getStatus() != Payout.PayoutStatus.PROCESSING) {
                return ResponseEntity.badRequest()
                        .body(Map.of("error", localizationService.getMessage("payout.error.onlyProcessingCanCancel", payout.getStatus().name())));
            }
            payoutService.markPayoutCancelled(id);
            return ResponseEntity.ok(Map.of("message", "Payout cancelled"));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().body(Map.of("error", e.getMessage()));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of("error", e.getMessage()));
        }
    }
}

