from datetime import datetime
import re
import unicodedata
from app.extensions import db
from sqlalchemy.event import listens_for

# Implementación propia de slugify usando la biblioteca estándar
def slugify(text):
    """Convierte texto a slug usando solo módulos estándar de Python."""
    text = unicodedata.normalize('NFKD', text).encode('ascii', 'ignore').decode('ascii')
    text = re.sub(r'[^\w\s-]', '', text.lower())
    return re.sub(r'[-\s]+', '-', text).strip('-_')

class Article(db.Model):
    __tablename__ = 'articles'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200), nullable=False)
    slug = db.Column(db.String(255), unique=True, index=True, nullable=False)
    summary = db.Column(db.Text, nullable=True) # Resumen corto
    content = db.Column(db.Text, nullable=False)
    featured_image = db.Column(db.String(255), nullable=True) # Ruta a la imagen destacada
    created_at = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    is_published = db.Column(db.Boolean, default=False, index=True)
    published_at = db.Column(db.DateTime, nullable=True)
    
    # En un entorno de desarrollo o para comenzar, podríamos hacer opcional la relación con usuario
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
    # 'author' se define en el backref de User.articles

    def __repr__(self):
        return f'<Article {self.id}: {self.title}>'
    
    @property
    def formatted_created_date(self):
        """Retorna fecha formateada como YYYY-MM-DD."""
        return self.created_at.strftime('%Y-%m-%d')
        
    def publish(self):
        """Marca el artículo como publicado y establece la fecha de publicación."""
        self.is_published = True
        self.published_at = datetime.utcnow()
        db.session.commit()
        return self
    
    def unpublish(self):
        """Cambia el estado del artículo a borrador."""
        self.is_published = False
        db.session.commit()
        return self
    
    def to_dict(self):
        """Convierte el modelo a un diccionario para fácil serialización."""
        # Crear diccionario con los campos básicos que sabemos que existen
        result = {
            'id': self.id,
            'title': self.title,
            'slug': self.slug,
            'summary': self.summary,
            'content': self.content,
            'is_published': self.is_published,
            'created_at': self.formatted_created_date,
        }
        
        # Añadir campos opcionales solo si existen en el modelo
        if hasattr(self, 'featured_image'):
            result['featured_image'] = self.featured_image
        else:
            result['featured_image'] = None
            
        if hasattr(self, 'published_at') and self.published_at:
            result['published_at'] = self.published_at.strftime('%Y-%m-%d')
        else:
            result['published_at'] = None
            
        return result


@listens_for(Article, 'before_insert')
@listens_for(Article, 'before_update')
def generate_slug(mapper, connect, target):
    """Genera automáticamente un slug único si no se proporciona uno."""
    # Sólo generar slug si no hay uno o si el título ha cambiado
    if not target.slug or not target.id:
        target.slug = slugify(target.title)
        
        # Verificar si el slug ya existe y añadir un sufijo si es necesario
        base_slug = target.slug
        counter = 1
        while Article.query.filter(Article.slug == target.slug, Article.id != target.id).first():
            target.slug = f"{base_slug}-{counter}"
            counter += 1
    
    # Si se marca como publicado y no tiene fecha de publicación, establecerla
    if target.is_published and not target.published_at:
        target.published_at = datetime.utcnow()
