package de.oaa.xxx.user;

import de.oaa.xxx.emailchange.EmailChangeRepository;
import de.oaa.xxx.games.bdsm.entity.AktiveSperreEntity;
import de.oaa.xxx.games.bdsm.entity.MitspielerEntity;
import de.oaa.xxx.games.bdsm.repository.AktiveSperreRepository;
import de.oaa.xxx.games.common.repository.AufgabeRepository;
import de.oaa.xxx.games.common.repository.AufgabenGruppeRepository;
import de.oaa.xxx.games.bdsm.repository.BdsmGameRepository;
import de.oaa.xxx.games.common.repository.FavoritRepository;
import de.oaa.xxx.games.common.repository.GruppenAboRepository;
import de.oaa.xxx.games.bdsm.repository.MitspielerRepository;
import de.oaa.xxx.games.common.repository.SperreRepository;
import de.oaa.xxx.games.common.repository.StrafeRepository;
import de.oaa.xxx.games.common.repository.ToyRepository;
import de.oaa.xxx.passwordreset.PasswordResetRepository;
import de.oaa.xxx.registration.Registration;
import de.oaa.xxx.social.entity.MessageCause;
import de.oaa.xxx.social.entity.NotificationPreferenceEntity;
import de.oaa.xxx.social.repository.KommentarLikeRepository;
import de.oaa.xxx.social.repository.KommentarRepository;
import de.oaa.xxx.social.repository.NotificationPreferenceRepository;
import de.oaa.xxx.social.repository.PinnwandEintragRepository;
import de.oaa.xxx.social.repository.PinnwandLikeRepository;
import de.oaa.xxx.social.repository.ProfileImageLikeRepository;
import de.oaa.xxx.social.repository.ProfileImageRepository;
import jakarta.transaction.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;

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

@Service
public class UserService {

    private static final Logger LOGGER = LoggerFactory.getLogger(UserService.class);

    private final UserRepository userRepository;
    private final AufgabenGruppeRepository aufgabenGruppeRepository;
    private final AufgabeRepository aufgabeRepository;
    private final StrafeRepository strafeRepository;
    private final SperreRepository sperreRepository;
    private final ToyRepository toyRepository;
    private final FavoritRepository favoritRepository;
    private final GruppenAboRepository gruppenAboRepository;
    private final BdsmGameRepository sessionRepository;
    private final AktiveSperreRepository aktiveSperreRepository;
    private final MitspielerRepository mitspielerRepository;
    private final EmailChangeRepository emailChangeRepository;
    private final PasswordResetRepository passwordResetRepository;
    private final ProfileImageRepository profileImageRepository;
    private final ProfileImageLikeRepository profileImageLikeRepository;
    private final PinnwandEintragRepository pinnwandEintragRepository;
    private final PinnwandLikeRepository pinnwandLikeRepository;
    private final KommentarRepository kommentarRepository;
    private final KommentarLikeRepository kommentarLikeRepository;
    private final NotificationPreferenceRepository notificationPreferenceRepository;

    public UserService(UserRepository userRepository,
                       AufgabenGruppeRepository aufgabenGruppeRepository,
                       AufgabeRepository aufgabeRepository,
                       StrafeRepository strafeRepository,
                       SperreRepository sperreRepository,
                       ToyRepository toyRepository,
                       FavoritRepository favoritRepository,
                       GruppenAboRepository gruppenAboRepository,
                       BdsmGameRepository sessionRepository,
                       AktiveSperreRepository aktiveSperreRepository,
                       MitspielerRepository mitspielerRepository,
                       EmailChangeRepository emailChangeRepository,
                       PasswordResetRepository passwordResetRepository,
                       ProfileImageRepository profileImageRepository,
                       ProfileImageLikeRepository profileImageLikeRepository,
                       PinnwandEintragRepository pinnwandEintragRepository,
                       PinnwandLikeRepository pinnwandLikeRepository,
                       KommentarRepository kommentarRepository,
                       KommentarLikeRepository kommentarLikeRepository,
                       NotificationPreferenceRepository notificationPreferenceRepository) {
        this.userRepository = userRepository;
        this.aufgabenGruppeRepository = aufgabenGruppeRepository;
        this.aufgabeRepository = aufgabeRepository;
        this.strafeRepository = strafeRepository;
        this.sperreRepository = sperreRepository;
        this.toyRepository = toyRepository;
        this.favoritRepository = favoritRepository;
        this.gruppenAboRepository = gruppenAboRepository;
        this.sessionRepository = sessionRepository;
        this.aktiveSperreRepository = aktiveSperreRepository;
        this.mitspielerRepository = mitspielerRepository;
        this.emailChangeRepository = emailChangeRepository;
        this.passwordResetRepository = passwordResetRepository;
        this.profileImageRepository = profileImageRepository;
        this.profileImageLikeRepository = profileImageLikeRepository;
        this.pinnwandEintragRepository = pinnwandEintragRepository;
        this.pinnwandLikeRepository = pinnwandLikeRepository;
        this.kommentarRepository = kommentarRepository;
        this.kommentarLikeRepository = kommentarLikeRepository;
        this.notificationPreferenceRepository = notificationPreferenceRepository;
    }

    /**
     * Liefert den UserEntity zum eingeloggten Principal.
     * Wirft 401 wenn der User nicht gefunden wird.
     */
    public UserEntity requireUser(Principal principal) {
        return userRepository.findByEmail(principal.getName())
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.UNAUTHORIZED));
    }

    /**
     * Löscht einen User-Account vollständig inklusive aller abhängigen Daten.
     * Gibt die gelöschte E-Mail zurück (wird für Cookie-Clearing im Controller benötigt).
     */
    @Transactional
    public void deleteAccount(UUID userId, String email) {
        var user = userRepository.findById(userId)
                .orElseThrow(() -> new IllegalArgumentException("User nicht gefunden: " + userId));

        LOGGER.info("Lösche Konto für User {}", email);

        // 1. AufgabenGruppen und deren Inhalte löschen
        var gruppen = aufgabenGruppeRepository.findByUserId(userId);
        if (!gruppen.isEmpty()) {
            aufgabeRepository.deleteAll(aufgabeRepository.findByAufgabenGruppeIn(gruppen));
            strafeRepository.deleteAll(strafeRepository.findByAufgabenGruppeIn(gruppen));
            sperreRepository.deleteAll(sperreRepository.findByAufgabenGruppeIn(gruppen));
            for (var gruppe : gruppen) {
                gruppenAboRepository.deleteByAufgabenGruppe(gruppe);
                favoritRepository.deleteByAufgabenGruppeId(gruppe.getGruppenId());
            }
            aufgabenGruppeRepository.deleteAll(gruppen);
        }

        // 2. Toys löschen
        toyRepository.deleteAll(toyRepository.findByUserId(userId));

        // 3. Eigene Favoriten und Gruppenabos löschen
        favoritRepository.deleteAll(favoritRepository.findByUserId(userId));
        gruppenAboRepository.deleteAll(gruppenAboRepository.findByUserId(userId));

        // 4. BDSM-Session mit Mitspieler und AktiveSperre löschen
        var sessionOpt = sessionRepository.findByUserId(userId);
        if (sessionOpt.isPresent()) {
            var session = sessionOpt.get();
            List<AktiveSperreEntity> sperren = session.getAktiveSperren();
            List<MitspielerEntity> mitspieler = session.getMitspieler();
            aktiveSperreRepository.deleteAll(sperren);
            mitspielerRepository.deleteAll(mitspieler);
            sessionRepository.delete(session);
        }

        // 5. Pending Tokens löschen
        emailChangeRepository.findByUserEmail(email).ifPresent(emailChangeRepository::delete);
        passwordResetRepository.findByEmail(email).ifPresent(passwordResetRepository::delete);

        // 5b. Profilbilder und Likes löschen
        var profileImages = profileImageRepository.findByUserIdOrderByUploadedAtDesc(userId);
        for (var img : profileImages) {
            profileImageLikeRepository.deleteByImageId(img.getImageId());
            kommentarRepository.findByTargetTypeAndTargetIdOrderByCreatedAtAsc("IMAGE", img.getImageId())
                    .forEach(k -> {
                        kommentarLikeRepository.deleteByKommentarId(k.getKommentarId());
                        kommentarRepository.delete(k);
                    });
        }
        profileImageRepository.deleteAll(profileImages);
        profileImageLikeRepository.deleteByUserId(userId);

        // 5c. Pinnwand-Einträge und Likes/Kommentare löschen
        var ownWallEntries = pinnwandEintragRepository.findByProfilUserIdOrderByCreatedAtDesc(userId);
        for (var e : ownWallEntries) {
            pinnwandLikeRepository.deleteByEintragId(e.getEintragId());
            kommentarRepository.findByTargetTypeAndTargetIdOrderByCreatedAtAsc("PINNWAND", e.getEintragId())
                    .forEach(k -> {
                        kommentarLikeRepository.deleteByKommentarId(k.getKommentarId());
                        kommentarRepository.delete(k);
                    });
        }
        pinnwandEintragRepository.deleteAll(ownWallEntries);
        pinnwandEintragRepository.deleteByAuthorId(userId);
        pinnwandLikeRepository.deleteByUserId(userId);
        kommentarRepository.deleteByAuthorId(userId);
        kommentarLikeRepository.deleteByUserId(userId);

        // 6. User löschen
        userRepository.delete(user);
    }

    /**
     * Legt einen neuen User aus einer bestätigten Registration an
     * und erstellt die Standard-Benachrichtigungseinstellungen.
     */
    public void createUser(Registration registration) {
        if (registration.getEmail() == null || registration.getPassword() == null || registration.getName() == null) {
            throw new IllegalArgumentException("E-Mail, Passwort und Name sind Pflichtfelder");
        }
        if (userRepository.findByEmail(registration.getEmail()).isPresent()) {
            LOGGER.warn("User mit E-Mail {} bereits vorhanden", registration.getEmail());
            throw new IllegalStateException("E-Mail bereits vorhanden");
        }

        UserEntity entity = new UserEntity();
        entity.setUserId(UUID.randomUUID());
        entity.setEmail(registration.getEmail());
        entity.setName(registration.getName());
        entity.setPassword(registration.getPassword());
        entity.setGeburtsdatum(registration.getGeburtsdatum());
        userRepository.save(entity);

        for (MessageCause cause : MessageCause.values()) {
            notificationPreferenceRepository.save(
                    NotificationPreferenceEntity.defaultFor(entity.getUserId(), cause));
        }

        LOGGER.info("User {} angelegt", entity.getUserId());
    }
}
