package de.oaa.xxx.admin;

import de.oaa.xxx.aufgaben.AufgabenGruppe;
import de.oaa.xxx.aufgaben.Toy;
import de.oaa.xxx.aufgaben.entity.AufgabenGruppeEntity;
import de.oaa.xxx.aufgaben.entity.ToyEntity;
import de.oaa.xxx.aufgaben.repository.AufgabenGruppeRepository;
import de.oaa.xxx.aufgaben.repository.ToyRepository;
import de.oaa.xxx.meldung.MeldungEntity;
import de.oaa.xxx.meldung.MeldungRepository;
import de.oaa.xxx.meldung.MeldungStatus;
import de.oaa.xxx.user.UserEntity;
import de.oaa.xxx.user.UserRepository;
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.*;

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

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

    private final AdminRepository adminRepository;
    private final UserRepository userRepository;
    private final MeldungRepository meldungRepository;
    private final AufgabenGruppeRepository aufgabenGruppeRepository;
    private final ToyRepository toyRepository;

    public AdminController(AdminRepository adminRepository, UserRepository userRepository,
                           MeldungRepository meldungRepository,
                           AufgabenGruppeRepository aufgabenGruppeRepository,
                           ToyRepository toyRepository) {
        this.adminRepository = adminRepository;
        this.userRepository = userRepository;
        this.meldungRepository = meldungRepository;
        this.aufgabenGruppeRepository = aufgabenGruppeRepository;
        this.toyRepository = toyRepository;
    }

    // ── DTOs ─────────────────────────────────────────────────────────────────

    record AdminDto(UUID adminId, UUID userId, String userName, AdminRolle rolle, LocalDateTime createdAt) {}

    record MeldungDto(UUID meldungId, UUID melderId, String melderName,
                      de.oaa.xxx.meldung.MeldungZielTyp zielTyp, UUID zielId,
                      String grund, LocalDateTime gemeldetAt,
                      MeldungStatus status, UUID bearbeitetVon, LocalDateTime bearbeitetAt) {}

    record CreateAdminRequest(UUID userId, AdminRolle rolle) {}

    record StatusRequest(MeldungStatus status) {}

    // ── Hilfsmethoden ────────────────────────────────────────────────────────

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

    private AdminEntity requireSuperAdmin(Principal principal) {
        AdminEntity admin = requireAdmin(principal);
        if (admin.getRolle() != AdminRolle.SUPERADMIN) {
            throw new org.springframework.web.server.ResponseStatusException(
                    org.springframework.http.HttpStatus.FORBIDDEN, "Kein Superadmin");
        }
        return admin;
    }

    private AdminDto toDto(AdminEntity e) {
        String name = userRepository.findById(e.getUserId()).map(UserEntity::getName).orElse("?");
        return new AdminDto(e.getAdminId(), e.getUserId(), name, e.getRolle(), e.getCreatedAt());
    }

    private MeldungDto toMeldungDto(MeldungEntity e) {
        String melderName = userRepository.findById(e.getMelderId()).map(UserEntity::getName).orElse("?");
        return new MeldungDto(e.getMeldungId(), e.getMelderId(), melderName,
                e.getZielTyp(), e.getZielId(), e.getGrund(), e.getGemeldetAt(),
                e.getStatus(), e.getBearbeitetVon(), e.getBearbeitetAt());
    }

    // ── /admin/me ────────────────────────────────────────────────────────────

    @GetMapping("/me")
    public ResponseEntity<AdminDto> me(Principal principal) {
        var user = userRepository.findByEmail(principal.getName()).orElse(null);
        if (user == null) return ResponseEntity.status(403).build();
        return adminRepository.findByUserId(user.getUserId())
                .map(a -> ResponseEntity.ok(toDto(a)))
                .orElse(ResponseEntity.status(403).build());
    }

    // ── Meldungen ────────────────────────────────────────────────────────────

    @GetMapping("/meldungen")
    public ResponseEntity<List<MeldungDto>> getMeldungen(
            @RequestParam(name = "status", required = false) MeldungStatus status,
            Principal principal) {
        requireAdmin(principal);
        List<MeldungEntity> list = status != null
                ? meldungRepository.findByStatusOrderByGemeldetAtDesc(status)
                : meldungRepository.findAllByOrderByGemeldetAtDesc();
        return ResponseEntity.ok(list.stream().map(this::toMeldungDto).toList());
    }

    @PutMapping("/meldungen/{id}")
    public ResponseEntity<Void> updateMeldung(@PathVariable("id") UUID id,
                                               @RequestBody StatusRequest body,
                                               Principal principal) {
        var admin = requireAdmin(principal);
        var user = userRepository.findByEmail(principal.getName()).orElseThrow();
        MeldungEntity meldung = meldungRepository.findById(id)
                .orElseThrow(() -> new org.springframework.web.server.ResponseStatusException(
                        org.springframework.http.HttpStatus.NOT_FOUND));
        meldung.setStatus(body.status());
        meldung.setBearbeitetVon(user.getUserId());
        meldung.setBearbeitetAt(LocalDateTime.now());
        return ResponseEntity.noContent().build();
    }

    // ── Aufgabengruppen ──────────────────────────────────────────────────────

    @GetMapping("/aufgabengruppen")
    public ResponseEntity<List<de.oaa.xxx.aufgaben.AufgabenGruppe>> getAufgabengruppen(Principal principal) {
        requireAdmin(principal);
        List<AufgabenGruppeEntity> list = aufgabenGruppeRepository
                .findByUserIdIsNull(PageRequest.of(0, 1000)).getContent();
        return ResponseEntity.ok(list.stream().map(AufgabenGruppeEntity::toAufgabenGruppe).toList());
    }

    @PostMapping("/aufgabengruppen")
    public ResponseEntity<de.oaa.xxx.aufgaben.AufgabenGruppeDisplay> createAufgabengruppe(
            @RequestBody AufgabenGruppe gruppe, Principal principal) {
        requireAdmin(principal);
        gruppe.setUserId(null);
        gruppe.setPrivateGruppe(false);
        AufgabenGruppeEntity entity = AufgabenGruppeEntity.create(gruppe);
        aufgabenGruppeRepository.save(entity);
        return ResponseEntity.status(201).body(entity.toAufgabenGruppeDisplay());
    }

    @PutMapping("/aufgabengruppen/{id}")
    public ResponseEntity<Void> updateAufgabengruppe(@PathVariable("id") UUID id,
                                                      @RequestBody AufgabenGruppe gruppe,
                                                      Principal principal) {
        requireAdmin(principal);
        AufgabenGruppeEntity entity = aufgabenGruppeRepository.findById(id)
                .orElseThrow(() -> new org.springframework.web.server.ResponseStatusException(
                        org.springframework.http.HttpStatus.NOT_FOUND));
        entity.setName(gruppe.getName());
        entity.setBeschreibung(gruppe.getBeschreibung());
        entity.setVon(gruppe.getVon());
        if (gruppe.getBild() != null) {
            entity.setBild(java.util.Base64.getDecoder().decode(gruppe.getBild()));
        }
        return ResponseEntity.noContent().build();
    }

    @DeleteMapping("/aufgabengruppen/{id}")
    public ResponseEntity<Void> deleteAufgabengruppe(@PathVariable("id") UUID id, Principal principal) {
        requireAdmin(principal);
        AufgabenGruppeEntity entity = aufgabenGruppeRepository.findById(id)
                .orElseThrow(() -> new org.springframework.web.server.ResponseStatusException(
                        org.springframework.http.HttpStatus.NOT_FOUND));
        if (entity.getUserId() != null) {
            return ResponseEntity.status(403).build(); // Nur System-Gruppen
        }
        aufgabenGruppeRepository.delete(entity);
        return ResponseEntity.noContent().build();
    }

    // ── Toys ─────────────────────────────────────────────────────────────────

    @GetMapping("/toys")
    public ResponseEntity<List<Toy>> getToys(Principal principal) {
        requireAdmin(principal);
        List<ToyEntity> list = toyRepository.findByUserIdIsNull(PageRequest.of(0, 1000, Sort.by(Sort.Direction.ASC, "name"))).getContent();
        return ResponseEntity.ok(list.stream().map(ToyEntity::toToy).toList());
    }

    @PostMapping("/toys")
    public ResponseEntity<Toy> createToy(@RequestBody Toy toy, Principal principal) {
        requireAdmin(principal);
        if (toyRepository.existsByNameIgnoreCaseAndUserIdIsNull(toy.getName())) {
            return ResponseEntity.status(409).build();
        }
        toy.setUserId(null);
        ToyEntity entity = ToyEntity.create(toy);
        toyRepository.save(entity);
        return ResponseEntity.status(201).body(entity.toToy());
    }

    @PutMapping("/toys/{id}")
    public ResponseEntity<Void> updateToy(@PathVariable("id") UUID id,
                                           @RequestBody Toy toy, Principal principal) {
        requireAdmin(principal);
        ToyEntity entity = toyRepository.findById(id)
                .orElseThrow(() -> new org.springframework.web.server.ResponseStatusException(
                        org.springframework.http.HttpStatus.NOT_FOUND));
        if (toyRepository.existsByNameIgnoreCaseAndUserIdIsNullAndToyIdNot(toy.getName(), id)) {
            return ResponseEntity.status(409).build();
        }
        entity.setName(toy.getName());
        entity.setBeschreibung(toy.getBeschreibung());
        if (toy.getBild() != null) {
            entity.setBild(java.util.Base64.getDecoder().decode(toy.getBild()));
        }
        return ResponseEntity.noContent().build();
    }

    @DeleteMapping("/toys/{id}")
    public ResponseEntity<Void> deleteToy(@PathVariable("id") UUID id, Principal principal) {
        requireAdmin(principal);
        ToyEntity entity = toyRepository.findById(id)
                .orElseThrow(() -> new org.springframework.web.server.ResponseStatusException(
                        org.springframework.http.HttpStatus.NOT_FOUND));
        long usage = toyRepository.countAufgabeUsage(id)
                + toyRepository.countStrafeUsage(id)
                + toyRepository.countSperreUsage(id);
        if (usage > 0) {
            return ResponseEntity.status(409).build();
        }
        toyRepository.delete(entity);
        return ResponseEntity.noContent().build();
    }

    // ── Admin-Verwaltung (nur SUPERADMIN) ────────────────────────────────────

    @GetMapping("/admins")
    public ResponseEntity<List<AdminDto>> getAdmins(Principal principal) {
        requireSuperAdmin(principal);
        return ResponseEntity.ok(adminRepository.findAll().stream().map(this::toDto).toList());
    }

    @PostMapping("/admins")
    public ResponseEntity<AdminDto> createAdmin(@RequestBody CreateAdminRequest request, Principal principal) {
        requireSuperAdmin(principal);
        if (!userRepository.existsById(request.userId())) {
            return ResponseEntity.status(404).build();
        }
        if (adminRepository.existsByUserId(request.userId())) {
            return ResponseEntity.status(409).build();
        }
        AdminEntity entity = AdminEntity.create(request.userId(), request.rolle());
        adminRepository.save(entity);
        return ResponseEntity.status(201).body(toDto(entity));
    }

    @DeleteMapping("/admins/{id}")
    public ResponseEntity<Void> deleteAdmin(@PathVariable("id") UUID id, Principal principal) {
        var requestingUser = userRepository.findByEmail(principal.getName()).orElseThrow();
        requireSuperAdmin(principal);
        AdminEntity entity = adminRepository.findById(id)
                .orElseThrow(() -> new org.springframework.web.server.ResponseStatusException(
                        org.springframework.http.HttpStatus.NOT_FOUND));
        if (entity.getUserId().equals(requestingUser.getUserId())) {
            return ResponseEntity.status(400).build(); // Selbstlöschung verhindern
        }
        adminRepository.delete(entity);
        return ResponseEntity.noContent().build();
    }
}
