package de.oaa.xxx.vorlieben;

import de.oaa.xxx.admin.AdminEntity;
import de.oaa.xxx.admin.AdminRepository;
import de.oaa.xxx.user.UserService;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.security.Principal;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/admin/vorlieben")
@Transactional
public class VorliebenAdminController {

    private final VorliebeKategorieRepository kategorieRepository;
    private final VorliebeItemRepository itemRepository;
    private final UserVorliebeRepository userVorliebeRepository;
    private final AdminRepository adminRepository;
    private final UserService userService;

    public VorliebenAdminController(VorliebeKategorieRepository kategorieRepository,
                                     VorliebeItemRepository itemRepository,
                                     UserVorliebeRepository userVorliebeRepository,
                                     AdminRepository adminRepository,
                                     UserService userService) {
        this.kategorieRepository    = kategorieRepository;
        this.itemRepository         = itemRepository;
        this.userVorliebeRepository = userVorliebeRepository;
        this.adminRepository        = adminRepository;
        this.userService            = userService;
    }

    private AdminEntity requireAdmin(Principal principal) {
        var user = userService.requireUser(principal);
        return adminRepository.findByUserId(user.getUserId())
                .orElseThrow(() -> new org.springframework.web.server.ResponseStatusException(
                        org.springframework.http.HttpStatus.FORBIDDEN, "Kein Admin"));
    }

    record KategorieRequest(String name, int sortOrder) {}
    record ItemRequest(UUID kategorieId, String name, int sortOrder) {}
    record KategorieDto(UUID kategorieId, String name, int sortOrder) {}
    record ItemDto(UUID itemId, UUID kategorieId, String name, int sortOrder) {}

    // ── Kategorien ────────────────────────────────────────────────────────────

    @GetMapping("/kategorien")
    public ResponseEntity<List<KategorieDto>> getKategorien(Principal principal) {
        requireAdmin(principal);
        List<KategorieDto> result = kategorieRepository.findAllByOrderBySortOrderAscNameAsc().stream()
                .map(k -> new KategorieDto(k.getKategorieId(), k.getName(), k.getSortOrder()))
                .toList();
        return ResponseEntity.ok(result);
    }

    @PostMapping("/kategorien")
    public ResponseEntity<KategorieDto> createKategorie(@RequestBody KategorieRequest req, Principal principal) {
        requireAdmin(principal);
        if (req.name() == null || req.name().isBlank()) return ResponseEntity.badRequest().build();
        VorliebeKategorieEntity entity = new VorliebeKategorieEntity();
        entity.setKategorieId(UUID.randomUUID());
        entity.setName(req.name().trim());
        entity.setSortOrder(req.sortOrder());
        kategorieRepository.save(entity);
        return ResponseEntity.status(201).body(
                new KategorieDto(entity.getKategorieId(), entity.getName(), entity.getSortOrder()));
    }

    @PutMapping("/kategorien/{id}")
    public ResponseEntity<Void> updateKategorie(@PathVariable("id") UUID id,
                                                 @RequestBody KategorieRequest req,
                                                 Principal principal) {
        requireAdmin(principal);
        if (req.name() == null || req.name().isBlank()) return ResponseEntity.badRequest().build();
        VorliebeKategorieEntity entity = kategorieRepository.findById(id).orElse(null);
        if (entity == null) return ResponseEntity.notFound().build();
        entity.setName(req.name().trim());
        entity.setSortOrder(req.sortOrder());
        kategorieRepository.save(entity);
        return ResponseEntity.ok().build();
    }

    @DeleteMapping("/kategorien/{id}")
    public ResponseEntity<Void> deleteKategorie(@PathVariable("id") UUID id, Principal principal) {
        requireAdmin(principal);
        if (!kategorieRepository.existsById(id)) return ResponseEntity.notFound().build();
        if (itemRepository.existsByKategorieId(id)) {
            return ResponseEntity.status(409)
                    .header("X-Error", "has-items")
                    .build();
        }
        kategorieRepository.deleteById(id);
        return ResponseEntity.ok().build();
    }

    // ── Items ─────────────────────────────────────────────────────────────────

    @GetMapping("/items")
    public ResponseEntity<List<ItemDto>> getItems(Principal principal) {
        requireAdmin(principal);
        List<ItemDto> result = itemRepository.findAllByOrderBySortOrderAscNameAsc().stream()
                .map(i -> new ItemDto(i.getItemId(), i.getKategorieId(), i.getName(), i.getSortOrder()))
                .toList();
        return ResponseEntity.ok(result);
    }

    @PostMapping("/items")
    public ResponseEntity<ItemDto> createItem(@RequestBody ItemRequest req, Principal principal) {
        requireAdmin(principal);
        if (req.name() == null || req.name().isBlank() || req.kategorieId() == null)
            return ResponseEntity.badRequest().build();
        if (!kategorieRepository.existsById(req.kategorieId()))
            return ResponseEntity.status(422).header("X-Error", "kategorie-not-found").build();
        VorliebeItemEntity entity = new VorliebeItemEntity();
        entity.setItemId(UUID.randomUUID());
        entity.setKategorieId(req.kategorieId());
        entity.setName(req.name().trim());
        entity.setSortOrder(req.sortOrder());
        itemRepository.save(entity);
        return ResponseEntity.status(201).body(
                new ItemDto(entity.getItemId(), entity.getKategorieId(), entity.getName(), entity.getSortOrder()));
    }

    @PutMapping("/items/{id}")
    public ResponseEntity<Void> updateItem(@PathVariable("id") UUID id,
                                            @RequestBody ItemRequest req,
                                            Principal principal) {
        requireAdmin(principal);
        if (req.name() == null || req.name().isBlank()) return ResponseEntity.badRequest().build();
        VorliebeItemEntity entity = itemRepository.findById(id).orElse(null);
        if (entity == null) return ResponseEntity.notFound().build();
        if (req.kategorieId() != null && !kategorieRepository.existsById(req.kategorieId()))
            return ResponseEntity.status(422).header("X-Error", "kategorie-not-found").build();
        if (req.kategorieId() != null) entity.setKategorieId(req.kategorieId());
        entity.setName(req.name().trim());
        entity.setSortOrder(req.sortOrder());
        itemRepository.save(entity);
        return ResponseEntity.ok().build();
    }

    @DeleteMapping("/items/{id}")
    public ResponseEntity<Void> deleteItem(@PathVariable("id") UUID id, Principal principal) {
        requireAdmin(principal);
        VorliebeItemEntity entity = itemRepository.findById(id).orElse(null);
        if (entity == null) return ResponseEntity.notFound().build();
        // Remove all user ratings for this item first
        List<UserVorliebeEntity> ratings = userVorliebeRepository.findAll().stream()
                .filter(uv -> uv.getItemId().equals(id)).toList();
        userVorliebeRepository.deleteAll(ratings);
        itemRepository.delete(entity);
        return ResponseEntity.ok().build();
    }

    // ── Export ────────────────────────────────────────────────────────────────

    record ExportKategorie(UUID kategorieId, String name, int sortOrder, List<ExportItem> items) {}
    record ExportItem(UUID itemId, String name, int sortOrder) {}

    @GetMapping("/export")
    public ResponseEntity<List<ExportKategorie>> export(Principal principal) {
        requireAdmin(principal);
        List<VorliebeKategorieEntity> kategorien = kategorieRepository.findAllByOrderBySortOrderAscNameAsc();
        List<VorliebeItemEntity> allItems = itemRepository.findAllByOrderBySortOrderAscNameAsc();
        Map<UUID, List<VorliebeItemEntity>> byKat = allItems.stream()
                .collect(Collectors.groupingBy(VorliebeItemEntity::getKategorieId));

        List<ExportKategorie> result = kategorien.stream()
                .map(k -> new ExportKategorie(
                        k.getKategorieId(), k.getName(), k.getSortOrder(),
                        byKat.getOrDefault(k.getKategorieId(), List.of()).stream()
                                .map(i -> new ExportItem(i.getItemId(), i.getName(), i.getSortOrder()))
                                .toList()))
                .toList();
        return ResponseEntity.ok()
                .header("Content-Disposition", "attachment; filename=\"vorlieben-export.json\"")
                .body(result);
    }

    // ── Import ────────────────────────────────────────────────────────────────

    record ImportItem(String name, int sortOrder) {}
    record ImportKategorie(String name, int sortOrder, List<ImportItem> items) {}
    record ImportResult(int kategorienCreated, int kategorienSkipped, int itemsCreated, int itemsSkipped) {}

    @PostMapping("/import")
    public ResponseEntity<ImportResult> importData(@RequestBody List<ImportKategorie> data,
                                                    Principal principal) {
        requireAdmin(principal);
        if (data == null) return ResponseEntity.badRequest().build();

        int kCreated = 0, kSkipped = 0, iCreated = 0, iSkipped = 0;
        List<VorliebeKategorieEntity> existingKategorien = kategorieRepository.findAllByOrderBySortOrderAscNameAsc();
        Map<String, VorliebeKategorieEntity> byName = existingKategorien.stream()
                .collect(Collectors.toMap(k -> k.getName().toLowerCase(), k -> k,
                        (a, b) -> a));

        for (ImportKategorie ik : data) {
            if (ik.name() == null || ik.name().isBlank()) { kSkipped++; continue; }
            VorliebeKategorieEntity kat = byName.get(ik.name().trim().toLowerCase());
            if (kat == null) {
                kat = new VorliebeKategorieEntity();
                kat.setKategorieId(UUID.randomUUID());
                kat.setName(ik.name().trim());
                kat.setSortOrder(ik.sortOrder());
                kategorieRepository.save(kat);
                byName.put(kat.getName().toLowerCase(), kat);
                kCreated++;
            } else {
                kSkipped++;
            }

            if (ik.items() == null) continue;
            final UUID katId = kat.getKategorieId();
            List<VorliebeItemEntity> existingItems =
                    itemRepository.findAllByOrderBySortOrderAscNameAsc().stream()
                            .filter(i -> i.getKategorieId().equals(katId))
                            .toList();
            Set<String> existingNames = existingItems.stream()
                    .map(i -> i.getName().toLowerCase()).collect(Collectors.toSet());

            for (ImportItem ii : ik.items()) {
                if (ii.name() == null || ii.name().isBlank()) { iSkipped++; continue; }
                if (existingNames.contains(ii.name().trim().toLowerCase())) { iSkipped++; continue; }
                VorliebeItemEntity item = new VorliebeItemEntity();
                item.setItemId(UUID.randomUUID());
                item.setKategorieId(katId);
                item.setName(ii.name().trim());
                item.setSortOrder(ii.sortOrder());
                itemRepository.save(item);
                iCreated++;
            }
        }
        return ResponseEntity.ok(new ImportResult(kCreated, kSkipped, iCreated, iSkipped));
    }
}
