import json
import re
from datetime import datetime, timezone
from typing import List, Optional
from uuid import UUID
from sqlalchemy.orm import Session
from .models import HelpArticle
from .schemas import HelpArticleCreate, HelpArticleUpdate, HelpSyncRequest, HelpSyncResponse

class HelpCenterService:
    @staticmethod
    def _inject_metadata(article: HelpArticle) -> HelpArticle:
        if not article or not article.content:
            return article
            
        # Look for <!-- a76_metadata: { ... } -->
        match = re.search(r'<!-- a76_metadata: (.*?) -->', article.content, re.DOTALL)
        if match:
            try:
                metadata = json.loads(match.group(1))
                article.content_type = metadata.get("content_type", "article")
                article.file_url = metadata.get("file_url")
                article.file_size = metadata.get("file_size")
                article.mime_type = metadata.get("mime_type")
                article.context_path = metadata.get("context_path")
                article.tags = metadata.get("tags")
                # Remove metadata from content for clean display if needed, 
                # but usually better to leave it and let parser handle it or hide it here.
                # For now, we just set the attributes.
            except Exception:
                pass
        else:
            article.content_type = "article"
            article.file_url = None
            article.file_size = None
            article.mime_type = None
            article.context_path = None
            article.tags = None
            
        return article

    @staticmethod
    def _extract_metadata(content: str, data: dict) -> str:
        # Remove existing metadata block if any
        content = re.sub(r'\n\n<!-- a76_metadata: .*? -->', '', content, flags=re.DOTALL)
        
        metadata = {
            "content_type": data.get("content_type", "article"),
            "file_url": data.get("file_url"),
            "file_size": data.get("file_size"),
            "mime_type": data.get("mime_type"),
            "context_path": data.get("context_path"),
            "tags": data.get("tags")
        }
        
        # Only append if there's something meaningful beyond "article"
        if (metadata["content_type"] != "article" or 
            metadata["file_url"] or 
            metadata["context_path"] or 
            metadata["tags"]):
            content += f"\n\n<!-- a76_metadata: {json.dumps(metadata)} -->"
            
        return content

    @staticmethod
    def get_all(db: Session) -> List[HelpArticle]:
        articles = db.query(HelpArticle).all()
        return [HelpCenterService._inject_metadata(a) for a in articles]

    @staticmethod
    def get_by_uuid(db: Session, article_uuid: UUID) -> Optional[HelpArticle]:
        article = db.query(HelpArticle).filter(HelpArticle.uuid == article_uuid).first()
        return HelpCenterService._inject_metadata(article)

    @staticmethod
    def get_by_slug(db: Session, slug: str) -> Optional[HelpArticle]:
        article = db.query(HelpArticle).filter(HelpArticle.slug == slug).first()
        return HelpCenterService._inject_metadata(article)

    @staticmethod
    def get_modifications(db: Session, since: datetime) -> List[HelpArticle]:
        # Ensure timezone awareness
        if since.tzinfo is None:
            since = since.replace(tzinfo=timezone.utc)
        articles = db.query(HelpArticle).filter(HelpArticle.updated_at > since).all()
        return [HelpCenterService._inject_metadata(a) for a in articles]

    @staticmethod
    def create(db: Session, article: HelpArticleCreate) -> HelpArticle:
        data = article.model_dump()
        # Move metadata into content
        data["content"] = HelpCenterService._extract_metadata(data["content"], data)
        # Remove virtual fields from data to avoid SQLAlchemy errors
        virtual_fields = ["content_type", "file_url", "file_size", "mime_type", "context_path", "tags"]
        for f in virtual_fields:
            if f in data:
                del data[f]
                
        db_article = HelpArticle(**data)
        db.add(db_article)
        db.commit()
        db.refresh(db_article)
        return HelpCenterService._inject_metadata(db_article)

    @staticmethod
    def update(db: Session, article_uuid: UUID, article_data: HelpArticleUpdate) -> Optional[HelpArticle]:
        db_article = db.query(HelpArticle).filter(HelpArticle.uuid == article_uuid).first()
        if not db_article:
            return None
        
        # Inject metadata to existing article to get current virtual fields
        db_article = HelpCenterService._inject_metadata(db_article)
        
        update_data = article_data.model_dump(exclude_unset=True)
        
        # Handle metadata update
        if "content" in update_data or any(f in update_data for f in ["content_type", "file_url", "file_size", "mime_type", "context_path", "tags"]):
            # Merge existing metadata with new updates
            current_meta = {
                "content_type": getattr(db_article, "content_type", "article"),
                "file_url": getattr(db_article, "file_url", None),
                "file_size": getattr(db_article, "file_size", None),
                "mime_type": getattr(db_article, "mime_type", None),
                "context_path": getattr(db_article, "context_path", None),
                "tags": getattr(db_article, "tags", None)
            }
            # Update with new data if present
            for f in ["content_type", "file_url", "file_size", "mime_type", "context_path", "tags"]:
                if f in update_data:
                    current_meta[f] = update_data[f]
            
            # Use current content or new content
            content = update_data.get("content", db_article.content)
            update_data["content"] = HelpCenterService._extract_metadata(content, current_meta)
            
        # Remove virtual fields from data
        virtual_fields = ["content_type", "file_url", "file_size", "mime_type", "context_path", "tags"]
        for f in virtual_fields:
            if f in update_data:
                del update_data[f]
                
        for key, value in update_data.items():
            setattr(db_article, key, value)
        
        db.commit()
        db.refresh(db_article)
        return HelpCenterService._inject_metadata(db_article)

    @staticmethod
    def delete(db: Session, article_uuid: UUID) -> bool:
        db_article = db.query(HelpArticle).filter(HelpArticle.uuid == article_uuid).first()
        if not db_article:
            return False
        db.delete(db_article)
        db.commit()
        return True

    @staticmethod
    def sync_article(db: Session, sync_data: HelpSyncRequest) -> HelpSyncResponse:
        """
        Lógica de sincronización "Smart Sync" (Last Write Wins).
        """
        db_article = db.query(HelpArticle).filter(HelpArticle.uuid == sync_data.article_uuid).first()
        
        client_updated_at = sync_data.client_updated_at
        if client_updated_at.tzinfo is None:
            client_updated_at = client_updated_at.replace(tzinfo=timezone.utc)

        if not db_article:
            # Caso A: Artículo nuevo desde el cliente
            # Store metadata in content
            client_meta = {
                "content_type": sync_data.client_content_type,
                "file_url": sync_data.client_file_url,
                "file_size": sync_data.client_file_size,
                "mime_type": sync_data.client_mime_type,
                "context_path": sync_data.client_context_path,
                "tags": sync_data.client_tags
            }
            content_with_meta = HelpCenterService._extract_metadata(sync_data.client_content, client_meta)
            
            new_article = HelpArticle(
                uuid=sync_data.article_uuid,
                slug=sync_data.client_slug,
                title=sync_data.client_title,
                content=content_with_meta,
                updated_at=client_updated_at,
                last_editor=sync_data.last_editor,
                category=sync_data.client_category,
                order=sync_data.client_order
            )
            db.add(new_article)
            db.commit()
            
            # Download assets if needed (Images in content and main file)
            from .utils import download_file_from_hub, sync_assets_from_content
            if sync_data.client_file_url:
                download_file_from_hub(sync_data.client_file_url)
            sync_assets_from_content(sync_data.client_content)
            
            return HelpSyncResponse(status="OK", message="Article created on server.")

        server_updated_at = db_article.updated_at
        if server_updated_at.tzinfo is None:
            server_updated_at = server_updated_at.replace(tzinfo=timezone.utc)

        # Caso A: Cliente es más nuevo
        if client_updated_at > server_updated_at:
            client_meta = {
                "content_type": sync_data.client_content_type,
                "file_url": sync_data.client_file_url,
                "file_size": sync_data.client_file_size,
                "mime_type": sync_data.client_mime_type,
                "context_path": sync_data.client_context_path,
                "tags": sync_data.client_tags
            }
            db_article.content = HelpCenterService._extract_metadata(sync_data.client_content, client_meta)
            db_article.title = sync_data.client_title
            db_article.slug = sync_data.client_slug
            db_article.updated_at = client_updated_at
            db_article.last_editor = sync_data.last_editor
            db_article.category = sync_data.client_category
            db_article.order = sync_data.client_order
            db.commit()

            # Download assets if needed (Images in content)
            from .utils import download_file_from_hub, sync_assets_from_content
            if sync_data.client_file_url:
                download_file_from_hub(sync_data.client_file_url)
            sync_assets_from_content(sync_data.client_content)

            return HelpSyncResponse(status="OK", message="Server updated with client data.")

        # Caso B: Servidor es más nuevo
        elif server_updated_at > client_updated_at:
            # Inject metadata for response
            db_article = HelpCenterService._inject_metadata(db_article)
            return HelpSyncResponse(
                status="UPDATE_REQUIRED",
                server_updated_at=server_updated_at,
                server_content=db_article.content,
                server_title=db_article.title,
                server_slug=db_article.slug,
                server_category=db_article.category,
                server_order=db_article.order,
                server_content_type=getattr(db_article, "content_type", "article"),
                server_file_url=getattr(db_article, "file_url", None),
                server_file_size=getattr(db_article, "file_size", None),
                server_mime_type=getattr(db_article, "mime_type", None),
                server_context_path=getattr(db_article, "context_path", None),
                server_tags=getattr(db_article, "tags", None),
                message="Client is outdated. Update required."
            )

        # Caso C: Iguales
        else:
            return HelpSyncResponse(status="OK", message="Already in sync.")
