package com.honey.honey.controller;

import com.honey.honey.dto.*;
import com.honey.honey.model.UserA;
import com.honey.honey.service.AdminUserService;
import com.honey.honey.service.UserService;
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.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.validation.Valid;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@RestController
@RequestMapping("/api/admin/users")
@RequiredArgsConstructor
public class AdminUserController {

    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()));
    }

    /** Sortable fields: UserA properties plus UserB/UserD (handled via custom query in service). */
    private static final Set<String> SORTABLE_FIELDS = Set.of(
            "id", "screenName", "telegramId", "telegramName", "isPremium",
            "languageCode", "countryCode", "deviceCode", "dateReg", "dateLogin", "banned",
            "balanceA", "depositTotal", "withdrawTotal", "referralCount", "profit"
    );
    private static final Set<String> DEPOSIT_SORT_FIELDS = Set.of("id", "usdAmount", "status", "orderId", "createdAt", "completedAt");
    private static final Set<String> WITHDRAWAL_SORT_FIELDS = Set.of("id", "usdAmount", "cryptoName", "amountToSend", "txhash", "status", "paymentId", "createdAt", "resolvedAt");

    private final AdminUserService adminUserService;
    private final UserService userService;

    @GetMapping
    @PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')")
    public ResponseEntity<Map<String, Object>> getUsers(
            @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 search,
            @RequestParam(required = false) Integer banned,
            @RequestParam(required = false) String countryCode,
            @RequestParam(required = false) String languageCode,
            @RequestParam(required = false) Integer dateRegFrom,
            @RequestParam(required = false) Integer dateRegTo,
            @RequestParam(required = false) Long balanceAMin,
            @RequestParam(required = false) Long balanceAMax,
            @RequestParam(required = false) Long balanceBMin,
            @RequestParam(required = false) Long balanceBMax,
            @RequestParam(required = false) Integer referralCountMin,
            @RequestParam(required = false) Integer referralCountMax,
            @RequestParam(required = false) Integer referrerId,
            @RequestParam(required = false) Integer referralLevel,
            @RequestParam(required = false) String ip,
            @RequestParam(required = false) Boolean botActive,
            @RequestParam(required = false) Integer depositCountMin) {

        // Build sort. Fields on UserB/UserD (balanceA, depositTotal, withdrawTotal, referralCount) are handled in service via custom query.
        Set<String> sortRequiresJoin = Set.of("balanceA", "depositTotal", "withdrawTotal", "referralCount", "profit");
        String effectiveSortBy = sortBy != null && sortBy.trim().isEmpty() ? null : (sortBy != null ? sortBy.trim() : null);
        if (effectiveSortBy != null && sortRequiresJoin.contains(effectiveSortBy)) {
            // Pass through; service will use custom ordered query
        } else if (effectiveSortBy != null && !SORTABLE_FIELDS.contains(effectiveSortBy)) {
            effectiveSortBy = null;
        }
        Sort sort = Sort.by("id").descending();
        if (effectiveSortBy != null && !sortRequiresJoin.contains(effectiveSortBy)) {
            Sort.Direction direction = "asc".equalsIgnoreCase(sortDir) ? Sort.Direction.ASC : Sort.Direction.DESC;
            sort = Sort.by(direction, effectiveSortBy);
        }
        Pageable pageable = PageRequest.of(page, size, sort);

        // Convert balance filters from display value to bigint format
        Long balanceAMinBigint = balanceAMin != null ? balanceAMin * 1000000L : null;
        Long balanceAMaxBigint = balanceAMax != null ? balanceAMax * 1000000L : null;
        Long balanceBMinBigint = balanceBMin != null ? balanceBMin * 1000000L : null;
        Long balanceBMaxBigint = balanceBMax != null ? balanceBMax * 1000000L : null;

        boolean excludeMasters = isSupport();
        Page<AdminUserDto> dtoPage = adminUserService.getUsers(
                pageable,
                search,
                banned,
                countryCode,
                languageCode,
                dateRegFrom,
                dateRegTo,
                balanceAMinBigint,
                balanceAMaxBigint,
                balanceBMinBigint,
                balanceBMaxBigint,
                referralCountMin,
                referralCountMax,
                referrerId,
                referralLevel,
                ip,
                botActive,
                depositCountMin,
                effectiveSortBy,
                sortDir,
                excludeMasters
        );

        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);
    }

    /**
     * Resolve Honey user ID from Telegram user ID.
     * Used by the Chatwoot embed when the contact has no honey_user_id set:
     * Chatwoot (Telegram channel) often uses Telegram user ID as contact identifier.
     */
    @GetMapping("/by-telegram-id")
    @PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')")
    public ResponseEntity<Map<String, Integer>> getUserByTelegramId(@RequestParam("telegram_id") Long telegramId) {
        if (telegramId == null) {
            return ResponseEntity.badRequest().build();
        }
        return userService.getUserByTelegramId(telegramId)
                .map(user -> ResponseEntity.ok(Map.of("id", user.getId())))
                .orElse(ResponseEntity.notFound().build());
    }

    @GetMapping("/{id}")
    @PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')")
    public ResponseEntity<AdminUserDetailDto> getUserDetail(@PathVariable Integer id) {
        AdminUserDetailDto userDetail = adminUserService.getUserDetail(id, isSupport());
        if (userDetail == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(userDetail);
    }

    @GetMapping("/{id}/transactions")
    @PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')")
    public ResponseEntity<Map<String, Object>> getUserTransactions(
            @PathVariable Integer id,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "50") int size) {
        
        Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());
        Page<AdminTransactionDto> transactions = adminUserService.getUserTransactions(id, pageable);
        
        Map<String, Object> response = new HashMap<>();
        response.put("content", transactions.getContent());
        response.put("totalElements", transactions.getTotalElements());
        response.put("totalPages", transactions.getTotalPages());
        response.put("currentPage", transactions.getNumber());
        response.put("size", transactions.getSize());
        response.put("hasNext", transactions.hasNext());
        response.put("hasPrevious", transactions.hasPrevious());
        
        return ResponseEntity.ok(response);
    }

    @GetMapping("/{id}/payments")
    @PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')")
    public ResponseEntity<Map<String, Object>> getUserPayments(
            @PathVariable Integer id,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size,
            @RequestParam(required = false) String sortBy,
            @RequestParam(required = false) String sortDir) {
        String field = sortBy != null && DEPOSIT_SORT_FIELDS.contains(sortBy.trim()) ? sortBy.trim() : "createdAt";
        Sort.Direction dir = "asc".equalsIgnoreCase(sortDir) ? Sort.Direction.ASC : Sort.Direction.DESC;
        Pageable pageable = PageRequest.of(page, size, Sort.by(dir, field));
        Page<UserDepositDto> deposits = adminUserService.getUserPayments(id, pageable);
        Map<String, Object> response = new HashMap<>();
        response.put("content", deposits.getContent());
        response.put("totalElements", deposits.getTotalElements());
        response.put("totalPages", deposits.getTotalPages());
        response.put("currentPage", deposits.getNumber());
        response.put("size", deposits.getSize());
        response.put("hasNext", deposits.hasNext());
        response.put("hasPrevious", deposits.hasPrevious());
        return ResponseEntity.ok(response);
    }

    @GetMapping("/{id}/payouts")
    @PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')")
    public ResponseEntity<Map<String, Object>> getUserPayouts(
            @PathVariable Integer id,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size,
            @RequestParam(required = false) String sortBy,
            @RequestParam(required = false) String sortDir) {
        String field = sortBy != null && WITHDRAWAL_SORT_FIELDS.contains(sortBy.trim()) ? sortBy.trim() : "createdAt";
        Sort.Direction dir = "asc".equalsIgnoreCase(sortDir) ? Sort.Direction.ASC : Sort.Direction.DESC;
        Pageable pageable = PageRequest.of(page, size, Sort.by(dir, field));
        Page<UserWithdrawalDto> payouts = adminUserService.getUserPayouts(id, pageable);
        Map<String, Object> response = new HashMap<>();
        response.put("content", payouts.getContent());
        response.put("totalElements", payouts.getTotalElements());
        response.put("totalPages", payouts.getTotalPages());
        response.put("currentPage", payouts.getNumber());
        response.put("size", payouts.getSize());
        response.put("hasNext", payouts.hasNext());
        response.put("hasPrevious", payouts.hasPrevious());
        return ResponseEntity.ok(response);
    }

    @GetMapping("/{id}/tasks")
    @PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')")
    public ResponseEntity<Map<String, Object>> getUserTasks(@PathVariable Integer id) {
        Map<String, Object> tasks = adminUserService.getUserTasks(id);
        return ResponseEntity.ok(tasks);
    }

    @PatchMapping("/{id}/ban")
    @PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')")
    public ResponseEntity<?> setUserBanned(
            @PathVariable Integer id,
            @RequestBody Map<String, Boolean> body) {
        Boolean banned = body != null ? body.get("banned") : null;
        if (banned == null) {
            return ResponseEntity.badRequest().body(Map.of("error", "banned is required (true/false)"));
        }
        try {
            adminUserService.setBanned(id, banned);
            return ResponseEntity.ok().build();
        } catch (IllegalArgumentException e) {
            return ResponseEntity.notFound().build();
        }
    }

    @PatchMapping("/{id}/withdrawals-enabled")
    @PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')")
    public ResponseEntity<?> setWithdrawalsEnabled(
            @PathVariable Integer id,
            @RequestBody Map<String, Boolean> body) {
        Boolean enabled = body != null ? body.get("enabled") : null;
        if (enabled == null) {
            return ResponseEntity.badRequest().body(Map.of("error", "enabled is required (true/false)"));
        }
        try {
            adminUserService.setWithdrawalsEnabled(id, enabled);
            return ResponseEntity.ok().build();
        } catch (IllegalArgumentException e) {
            return ResponseEntity.notFound().build();
        }
    }

    @PostMapping("/{id}/balance/adjust")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<?> adjustBalance(
            @PathVariable Integer id,
            @Valid @RequestBody com.honey.honey.dto.BalanceAdjustmentRequest request) {
        try {
            com.honey.honey.dto.BalanceAdjustmentResponse response = adminUserService.adjustBalance(id, request);
            return ResponseEntity.ok(response);
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().body(Map.of("error", e.getMessage()));
        }
    }
}

