"""Service pour la gestion des histoires."""

from typing import Optional, List
from datetime import datetime
from models.story import Story, db
from models.lorebook import LoreBook
from schemas.story import StoryCreateSchema, StoryUpdateSchema
from services.ai_service import AIService


class StoryService:
    """Service pour la gestion des histoires."""
    
    @staticmethod
    def create_story(user_id: str, data: StoryCreateSchema) -> Story:
        """Crée une nouvelle histoire.
        
        Si un pitch est fourni, l'IA analyse le pitch et extrait les paramètres.
        Sinon, utilise les paramètres fournis manuellement.
        
        Args:
            user_id: ID de l'utilisateur créateur.
            data: Données de création validées.
        
        Returns:
            Story créée.
        
        Raises:
            ValueError: Si ni pitch ni titre n'est fourni.
        """
        # Mode pitch : analyser avec l'IA ET permettre surcharges manuelles
        if data.pitch:
            analyzed = AIService.analyze_pitch(data.pitch, data.title)
            
            # Utiliser les paramètres fournis par l'utilisateur en priorité, sinon ceux de l'IA
            title = data.title or analyzed.get('title')
            genre = data.genre or analyzed.get('genre')
            epoch = data.epoch or analyzed.get('epoch')
            reality_level = data.reality_level if data.reality_level is not None else analyzed.get('reality_level', 70)
            narrative_perspective = data.narrative_perspective or analyzed.get('narrative_perspective', 'second')
            protagonist_name = data.protagonist_name or analyzed.get('protagonist_name')
            protagonist_gender = data.protagonist_gender or analyzed.get('protagonist_gender')
        else:
            # Mode manuel pur
            if not data.title:
                raise ValueError("Un titre ou un pitch est requis")
            
            title = data.title
            genre = data.genre
            epoch = data.epoch
            reality_level = data.reality_level if data.reality_level is not None else 70
            narrative_perspective = data.narrative_perspective or 'second'
            protagonist_name = data.protagonist_name
            protagonist_gender = data.protagonist_gender
        
        # Créer l'histoire avec les paramètres
        story = Story(
            user_id=user_id,
            title=title,
            pitch=data.pitch,  # Conserver le pitch original
            genre=genre,
            epoch=epoch,
            reality_level=reality_level,
            narrative_perspective=narrative_perspective,
            protagonist_name=protagonist_name,
            protagonist_gender=protagonist_gender,
            game_mode=data.game_mode,
            status='in_progress'
        )
        
        db.session.add(story)
        db.session.flush()  # Pour obtenir l'ID
        
        # Créer le LoreBook associé
        lorebook = LoreBook(
            story_id=story.id,
            characters=[],
            locations=[],
            items=[],
            key_events=[],
            protagonist_state={}
        )
        
        db.session.add(lorebook)
        db.session.commit()
        
        return story
    
    @staticmethod
    def get_story_by_id(story_id: str) -> Optional[Story]:
        """Récupère une histoire par son ID.
        
        Args:
            story_id: ID de l'histoire.
        
        Returns:
            Story ou None si non trouvée.
        """
        return Story.query.get(story_id)
    
    @staticmethod
    def get_user_stories(user_id: str) -> List[Story]:
        """Récupère toutes les histoires d'un utilisateur.
        
        Args:
            user_id: ID de l'utilisateur.
        
        Returns:
            Liste des histoires.
        """
        return Story.query.filter_by(user_id=user_id)\
            .order_by(Story.last_played_at.desc())\
            .all()
    
    @staticmethod
    def update_story(story: Story, data: StoryUpdateSchema) -> Story:
        """Met à jour une histoire.
        
        Args:
            story: Histoire à mettre à jour.
            data: Données de mise à jour validées.
        
        Returns:
            Story mise à jour.
        """
        if data.title is not None:
            story.title = data.title
        if data.status is not None:
            story.status = data.status
        if data.game_mode is not None:
            story.game_mode = data.game_mode
        if data.publication_description is not None:
            story.publication_description = data.publication_description
        
        db.session.commit()
        return story
    
    @staticmethod
    def delete_story(story: Story) -> None:
        """Supprime une histoire.
        
        Args:
            story: Histoire à supprimer.
        """
        db.session.delete(story)
        db.session.commit()
    
    @staticmethod
    def publish_story(story: Story, publication_status: str = 'ongoing') -> Story:
        """Publie une histoire (ou continue la publication).
        
        Args:
            story: Histoire à publier.
            publication_status: 'ongoing' ou 'finished'.
        
        Returns:
            Story publiée.
        """
        if not story.is_published:
            # Première publication
            story.is_published = True
            story.published_at = datetime.utcnow()
            story.publication_status = publication_status
            story.published_turn_count = story.turn_count
            
            # Marquer tous les turns actuels comme publiés
            for turn in story.turns:
                if not turn.is_published:
                    turn.is_published = True
        else:
            # Mise à jour du statut de publication
            story.publication_status = publication_status
            story.last_chapter_published_at = datetime.utcnow()
            
            # Publier les nouveaux turns non encore publiés
            for turn in story.turns:
                if not turn.is_published:
                    turn.is_published = True
            
            story.published_turn_count = story.turn_count
        
        db.session.commit()
        return story
    
    @staticmethod
    def get_published_stories(
        genre: Optional[str] = None,
        status: Optional[str] = None,
        limit: int = 20,
        offset: int = 0
    ) -> List[Story]:
        """Récupère les histoires publiées avec filtres.
        
        Args:
            genre: Filtrer par genre (optionnel).
            status: Filtrer par statut de publication (optionnel).
            limit: Nombre maximum d'histoires à retourner.
            offset: Offset pour la pagination.
        
        Returns:
            Liste des histoires publiées.
        """
        query = Story.query.filter_by(is_published=True)
        
        if genre:
            query = query.filter_by(genre=genre)
        if status:
            query = query.filter_by(publication_status=status)
        
        return query.order_by(Story.published_at.desc())\
            .limit(limit)\
            .offset(offset)\
            .all()

