package de.oaa.xxx.games.vanilla.controller;

import java.security.Principal;
import java.util.List;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import de.oaa.xxx.games.common.aufgaben.AufgabenGruppe;
import de.oaa.xxx.games.common.aufgaben.AufgabenGruppePage;
import de.oaa.xxx.games.common.entity.AufgabenGruppeEntity;
import de.oaa.xxx.games.common.entity.GruppenAboEntity;
import de.oaa.xxx.games.common.repository.AufgabenGruppeRepository;
import de.oaa.xxx.games.common.repository.GruppenAboRepository;
import de.oaa.xxx.user.UserEntity;
import de.oaa.xxx.user.UserService;

@RestController
@RequestMapping("/vanilla/abo")
@Transactional
public class VanillaAboController {

    private static final Logger LOGGER = LoggerFactory.getLogger(VanillaAboController.class);
    private static final int DEFAULT_PAGE_SIZE = 5;
    private static final int DISCOVER_PAGE_SIZE = 10;

    private final GruppenAboRepository aboRepository;
    private final AufgabenGruppeRepository gruppeRepository;
    private final UserService userService;

    public VanillaAboController(GruppenAboRepository aboRepository,
                                 AufgabenGruppeRepository gruppeRepository,
                                 UserService userService) {
        this.aboRepository = aboRepository;
        this.gruppeRepository = gruppeRepository;
        this.userService = userService;
    }

    // ── Abonnierte Gruppen laden (nur vanilla-safe) ──

    @GetMapping("/list")
    public ResponseEntity<AufgabenGruppePage> listSubscribed(
            @RequestParam(name = "page", defaultValue = "0") int page,
            @RequestParam(name = "size", defaultValue = "" + DEFAULT_PAGE_SIZE) int size,
            Principal principal) {
        UserEntity user = userService.requireUser(principal);

        Page<GruppenAboEntity> dbPage = aboRepository.findByUserIdWithContent(
                user.getUserId(), PageRequest.of(page, size, Sort.by("aufgabenGruppe.name")));
        List<AufgabenGruppe> dtos = dbPage.getContent().stream()
                .map(a -> enrich(a.getAufgabenGruppe(), user.getUserId(), true))
                .toList();
        AufgabenGruppePage result = new AufgabenGruppePage();
        result.setContent(dtos);
        result.setCurrentPage(dbPage.getNumber());
        result.setTotalPages(dbPage.getTotalPages());
        result.setTotalElements(dbPage.getTotalElements());
        return ResponseEntity.ok(result);
    }

    // ── Entdecken (nur vanilla-safe Gruppen von anderen) ──

    @GetMapping("/discover")
    public ResponseEntity<AufgabenGruppePage> discover(
            @RequestParam(required = false) String name,
            @RequestParam(name = "page", defaultValue = "0") int page,
            @RequestParam(name = "size", defaultValue = "" + DISCOVER_PAGE_SIZE) int size,
            Principal principal) {
        UserEntity user = userService.requireUser(principal);

        String namePattern = name != null && !name.isBlank() ? "%" + name.trim() + "%" : null;

        List<AufgabenGruppe> dtos = gruppeRepository
                .findVanillaSafePublicFromOthers(user.getUserId(), namePattern).stream()
                .map(g -> enrich(g, user.getUserId(), aboRepository.existsByUserIdAndAufgabenGruppe(user.getUserId(), g)))
                .sorted(java.util.Comparator.comparingLong(AufgabenGruppe::getSubscriberCount).reversed()
                        .thenComparing(AufgabenGruppe::getName, String.CASE_INSENSITIVE_ORDER))
                .toList();

        int total = dtos.size();
        int start = page * size;
        List<AufgabenGruppe> content = start >= total ? List.of() : dtos.subList(start, Math.min(start + size, total));
        AufgabenGruppePage discoverPage = new AufgabenGruppePage();
        discoverPage.setContent(content);
        discoverPage.setCurrentPage(page);
        discoverPage.setTotalPages(total == 0 ? 1 : (int) Math.ceil((double) total / size));
        discoverPage.setTotalElements(total);
        return ResponseEntity.ok(discoverPage);
    }

    // ── Abonnieren (nur vanilla-safe) ──

    @PostMapping("/{gruppenId}")
    public ResponseEntity<Void> subscribe(@PathVariable("gruppenId") UUID gruppenId, Principal principal) {
        UserEntity user = userService.requireUser(principal);

        AufgabenGruppeEntity gruppe = gruppeRepository.findById(gruppenId).orElse(null);
        if (gruppe == null || gruppe.isPrivateGruppe() || user.getUserId().equals(gruppe.getUserId())) {
            return ResponseEntity.badRequest().build();
        }
        // Vanilla-safe validation
        if (!gruppe.getStrafen().isEmpty() || !gruppe.getSperren().isEmpty()) {
            return ResponseEntity.status(403).build();
        }
        if (aboRepository.existsByUserIdAndAufgabenGruppe(user.getUserId(), gruppe)) {
            return ResponseEntity.ok().build();
        }
        GruppenAboEntity abo = new GruppenAboEntity();
        abo.setAboId(UUID.randomUUID());
        abo.setUserId(user.getUserId());
        abo.setAufgabenGruppe(gruppe);
        aboRepository.save(abo);
        LOGGER.info("User {} hat Vanilla-Gruppe {} abonniert", user.getUserId(), gruppenId);
        return ResponseEntity.status(201).build();
    }

    // ── Abonnement kündigen ──

    @DeleteMapping("/{gruppenId}")
    public ResponseEntity<Void> unsubscribe(@PathVariable("gruppenId") UUID gruppenId, Principal principal) {
        UserEntity user = userService.requireUser(principal);

        AufgabenGruppeEntity gruppe = gruppeRepository.findById(gruppenId).orElse(null);
        if (gruppe == null) return ResponseEntity.noContent().build();

        aboRepository.deleteByUserIdAndAufgabenGruppe(user.getUserId(), gruppe);
        LOGGER.info("User {} hat Vanilla-Abo auf Gruppe {} beendet", user.getUserId(), gruppenId);
        return ResponseEntity.accepted().build();
    }

    // ── Hilfsmethoden ──

    private AufgabenGruppe enrich(AufgabenGruppeEntity entity, UUID userId, boolean subscribed) {
        AufgabenGruppe g = entity.toAufgabenGruppe();
        g.setSubscriberCount(aboRepository.countByAufgabenGruppe(entity));
        g.setSubscribed(subscribed);
        return g;
    }


}
