package pl.polskalokalnie.admin;

import java.util.Comparator;
import java.util.List;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;
import pl.polskalokalnie.moderation.ForbiddenWordResponse;
import pl.polskalokalnie.moderation.TextModerationService;
import pl.polskalokalnie.auth.dto.UserResponse;
import pl.polskalokalnie.listing.ListingResponse;
import pl.polskalokalnie.listing.ListingService;
import pl.polskalokalnie.listing.ListingStatus;
import pl.polskalokalnie.message.MessageResponse;
import pl.polskalokalnie.message.MessageService;
import pl.polskalokalnie.message.SendMessageRequest;
import pl.polskalokalnie.report.ListingReportResponse;
import pl.polskalokalnie.report.ListingReportService;
import pl.polskalokalnie.report.ResolveListingReportRequest;
import pl.polskalokalnie.user.AppUser;
import pl.polskalokalnie.user.BlockedEmail;
import pl.polskalokalnie.user.BlockedEmailRepository;
import pl.polskalokalnie.user.Role;
import pl.polskalokalnie.user.UserRepository;

@RestController
@RequestMapping("/api/admin")
public class AdminController {

    private final UserRepository userRepository;
    private final BlockedEmailRepository blockedEmailRepository;
    private final ListingService listingService;
    private final ListingReportService listingReportService;
    private final MessageService messageService;
    private final TextModerationService textModerationService;

    public AdminController(UserRepository userRepository, BlockedEmailRepository blockedEmailRepository,
            ListingService listingService, ListingReportService listingReportService,
            MessageService messageService,
            TextModerationService textModerationService) {
        this.userRepository = userRepository;
        this.blockedEmailRepository = blockedEmailRepository;
        this.listingService = listingService;
        this.listingReportService = listingReportService;
        this.messageService = messageService;
        this.textModerationService = textModerationService;
    }

    // --- Uzytkownicy ---

    @GetMapping("/users")
    public List<UserResponse> users() {
        return userRepository.findAll().stream()
                .sorted(Comparator.comparing(AppUser::getCreatedAt).reversed())
                .map(UserResponse::from)
                .toList();
    }

    @PostMapping("/users/{id}/block")
    public UserResponse block(@PathVariable Long id) {
        return setBlocked(id, true);
    }

    @PostMapping("/users/{id}/unblock")
    public UserResponse unblock(@PathVariable Long id) {
        return setBlocked(id, false);
    }

    @PostMapping("/users/{id}/verify")
    public UserResponse verify(@PathVariable Long id) {
        AppUser user = requireUser(id);
        user.setVerified(true);
        return UserResponse.from(userRepository.save(user));
    }

    @DeleteMapping("/users/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void deleteUser(@PathVariable Long id) {
        AppUser user = requireUser(id);
        if (user.getRole() == Role.ADMIN) {
            throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Nie można usunąć konta administratora");
        }
        userRepository.delete(user);
    }

    // Odrzucenie konta podczas weryfikacji: e-mail trafia na trwala liste zablokowanych
    // adresow, wiec nie da sie nim ponownie zalozyc konta.
    @PostMapping("/users/{id}/reject")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void rejectUser(@PathVariable Long id) {
        AppUser user = requireUser(id);
        if (user.getRole() == Role.ADMIN) {
            throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Nie można odrzucić konta administratora");
        }
        if (!blockedEmailRepository.existsByEmailIgnoreCase(user.getEmail())) {
            BlockedEmail blockedEmail = new BlockedEmail();
            blockedEmail.setEmail(user.getEmail());
            blockedEmailRepository.save(blockedEmail);
        }
        userRepository.delete(user);
    }

    private UserResponse setBlocked(Long id, boolean blocked) {
        AppUser user = requireUser(id);
        if (user.getRole() == Role.ADMIN) {
            throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Nie można zablokować konta administratora");
        }
        user.setBlocked(blocked);
        return UserResponse.from(userRepository.save(user));
    }

    private AppUser requireUser(Long id) {
        return userRepository.findById(id)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Użytkownik nie istnieje"));
    }

    // --- Wiadomosci do uzytkownika ---

    @GetMapping("/users/{id}/messages")
    public List<MessageResponse> userMessages(@PathVariable Long id, Authentication authentication) {
        AppUser user = requireUser(id);
        AppUser admin = requireAdmin(authentication);
        return messageService.getConversation(admin.getId(), user.getId());
    }

    @PostMapping("/users/{id}/messages")
    public MessageResponse sendMessageToUser(@PathVariable Long id, Authentication authentication,
            @Valid @RequestBody SendMessageRequest request) {
        AppUser user = requireUser(id);
        AppUser admin = requireAdmin(authentication);
        return messageService.send(admin.getId(), user.getId(), request.content());
    }

    private AppUser requireAdmin(Authentication authentication) {
        return userRepository.findByEmailIgnoreCase(authentication.getName())
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.UNAUTHORIZED));
    }

    // --- Moderacja ogloszen ---

    @GetMapping("/listings")
    public List<ListingResponse> listings() {
        return listingService.findAllForModeration();
    }

    @PostMapping("/listings/{id}/approve")
    public ListingResponse approve(@PathVariable Long id) {
        return listingService.changeStatus(id, ListingStatus.APPROVED);
    }

    @PostMapping("/listings/{id}/reject")
    public ListingResponse reject(@PathVariable Long id) {
        return listingService.changeStatus(id, ListingStatus.REJECTED);
    }

    @DeleteMapping("/listings/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void deleteListing(@PathVariable Long id) {
        listingService.delete(id);
    }

    @GetMapping("/reports")
    public List<ListingReportResponse> reports() {
        return listingReportService.findAllForAdmin();
    }

    @PostMapping("/reports/{id}/resolve")
    public ListingReportResponse resolveReport(
            @PathVariable Long id,
            Authentication authentication,
            @RequestBody(required = false) ResolveListingReportRequest request
    ) {
        return listingReportService.resolve(id, authentication.getName(), request == null ? null : request.note());
    }

    @PostMapping("/reports/{id}/delete-listing")
    public ListingReportResponse deleteListingFromReport(@PathVariable Long id, Authentication authentication) {
        return listingReportService.deleteListingAndResolve(id, authentication.getName());
    }

    // --- Slowa zabronione ---

    @GetMapping("/forbidden-words")
    public List<ForbiddenWordResponse> forbiddenWords() {
        return textModerationService.listForbiddenWords();
    }

    @PostMapping("/forbidden-words")
    @ResponseStatus(HttpStatus.CREATED)
    public List<ForbiddenWordResponse> addForbiddenWord(@Valid @RequestBody AddForbiddenWordRequest request) {
        return textModerationService.addForbiddenWord(request.word());
    }

    @DeleteMapping("/forbidden-words/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void deleteForbiddenWord(@PathVariable Long id) {
        textModerationService.removeForbiddenWord(id);
    }
}
