package com.loremind.application.gamesystemcontext;

import com.loremind.domain.gamesystemcontext.GameSystem;
import com.loremind.domain.gamesystemcontext.RulesImportResult;
import com.loremind.domain.gamesystemcontext.ports.GameSystemRepository;
import com.loremind.domain.gamesystemcontext.ports.RulesPdfImporter;
import com.loremind.domain.shared.template.TemplateField;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class GameSystemService {

    private final GameSystemRepository gameSystemRepository;
    private final RulesPdfImporter rulesPdfImporter;

    public GameSystemService(GameSystemRepository gameSystemRepository,
                             RulesPdfImporter rulesPdfImporter) {
        this.gameSystemRepository = gameSystemRepository;
        this.rulesPdfImporter = rulesPdfImporter;
    }

    /**
     * Importe un PDF de règles et renvoie une PROPOSITION de sections (titre →
     * markdown). Ne persiste rien : l'UI laisse l'utilisateur réviser/éditer
     * puis enregistrer le GameSystem via {@link #updateGameSystem}/{@link #createGameSystem}.
     */
    public RulesImportResult importRulesFromPdf(byte[] pdfBytes, String filename) {
        return rulesPdfImporter.importRules(pdfBytes, filename);
    }

    /**
     * Variante streamée de {@link #importRulesFromPdf} : remonte l'avancement via
     * callbacks (import long → l'UI affiche une progression). Ne persiste rien.
     */
    public void importRulesFromPdfStreaming(
            byte[] pdfBytes,
            String filename,
            java.util.function.Consumer<com.loremind.domain.gamesystemcontext.RulesImportProgress> onProgress,
            Runnable onHeartbeat,
            java.util.function.Consumer<RulesImportResult> onDone,
            java.util.function.Consumer<Throwable> onError) {
        rulesPdfImporter.importRulesStreaming(
                pdfBytes, filename, onProgress, onHeartbeat, onDone, onError);
    }

    /**
     * Parameter Object pour la création / mise à jour d'un GameSystem.
     * Les templates peuvent etre null (interpretes comme listes vides).
     */
    public record GameSystemData(
            String name,
            String description,
            String rulesMarkdown,
            List<TemplateField> characterTemplate,
            List<TemplateField> npcTemplate,
            String author,
            boolean isPublic
    ) {}

    public GameSystem createGameSystem(GameSystemData data) {
        GameSystem gameSystem = GameSystem.builder()
                .name(data.name())
                .description(data.description())
                .rulesMarkdown(data.rulesMarkdown())
                .author(normalize(data.author()))
                .isPublic(data.isPublic())
                .build();
        gameSystem.replaceCharacterTemplate(data.characterTemplate());
        gameSystem.replaceNpcTemplate(data.npcTemplate());
        return gameSystemRepository.save(gameSystem);
    }

    public Optional<GameSystem> getGameSystemById(String id) {
        return gameSystemRepository.findById(id);
    }

    public List<GameSystem> getAllGameSystems() {
        return gameSystemRepository.findAll();
    }

    public GameSystem updateGameSystem(String id, GameSystemData data) {
        GameSystem existing = gameSystemRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("GameSystem non trouvé avec l'ID: " + id));
        existing.setName(data.name());
        existing.setDescription(data.description());
        existing.setRulesMarkdown(data.rulesMarkdown());
        existing.replaceCharacterTemplate(data.characterTemplate());
        existing.replaceNpcTemplate(data.npcTemplate());
        existing.setAuthor(normalize(data.author()));
        existing.setPublic(data.isPublic());
        return gameSystemRepository.save(existing);
    }

    public void deleteGameSystem(String id) {
        gameSystemRepository.deleteById(id);
    }

    public boolean gameSystemExists(String id) {
        return gameSystemRepository.existsById(id);
    }

    public List<GameSystem> searchGameSystems(String query) {
        if (query == null || query.isBlank()) return List.of();
        return gameSystemRepository.searchByName(query.trim());
    }

    private String normalize(String value) {
        return (value == null || value.isBlank()) ? null : value;
    }
}
