from fastapi import APIRouter, Depends, HTTPException, status, Request, UploadFile, File
from sqlalchemy.orm import Session
from typing import Optional
from datetime import datetime
from pathlib import Path
import json
import os
import aiofiles
import uuid
from pydantic import ValidationError
from ...shared.config.database import get_db
from ...shared.config.logging_config import get_logger
from ...security.middleware.auth import get_current_user, authorize_roles
from ...auth.models.user import User
from ..models.page_content import PageContent, PageType
from ..schemas.page_content import PageContentUpdateRequest
from ...shared.utils.sanitization import sanitize_html
logger = get_logger(__name__)
router = APIRouter(prefix='/page-content', tags=['page-content'])

def build_content_dict(content: PageContent) -> dict:
    """Helper function to build content dictionary from PageContent model."""
    json_fields = ['contact_info', 'social_links', 'footer_links', 'badges', 'values', 'features', 
                   'amenities', 'testimonials', 'gallery_images', 'stats', 'luxury_features', 
                   'luxury_gallery', 'luxury_testimonials', 'luxury_services', 'luxury_experiences', 
                   'awards', 'partners', 'team', 'timeline', 'achievements', 'sections_enabled',
                   'trust_badges', 'promotions']
    
    def parse_json_field(field_value):
        if field_value is None:
            return None
        try:
            return json.loads(field_value) if isinstance(field_value, str) else field_value
        except (json.JSONDecodeError, TypeError):
            return field_value
    
    return {
        'id': content.id,
        'page_type': content.page_type.value,
        'title': content.title,
        'subtitle': content.subtitle,
        'description': content.description,
        'content': content.content,
        'meta_title': content.meta_title,
        'meta_description': content.meta_description,
        'meta_keywords': content.meta_keywords,
        'og_title': content.og_title,
        'og_description': content.og_description,
        'og_image': content.og_image,
        'canonical_url': content.canonical_url,
        'contact_info': parse_json_field(content.contact_info),
        'map_url': content.map_url,
        'social_links': parse_json_field(content.social_links),
        'footer_links': parse_json_field(content.footer_links),
        'badges': parse_json_field(content.badges),
        'copyright_text': content.copyright_text,
        'hero_title': content.hero_title,
        'hero_subtitle': content.hero_subtitle,
        'hero_image': content.hero_image,
        'hero_video_url': content.hero_video_url,
        'hero_video_poster': content.hero_video_poster,
        'story_content': content.story_content,
        'values': parse_json_field(content.values),
        'features': parse_json_field(content.features),
        'features_section_title': content.features_section_title,
        'features_section_subtitle': content.features_section_subtitle,
        'about_hero_image': content.about_hero_image,
        'mission': content.mission,
        'vision': content.vision,
        'team': parse_json_field(content.team),
        'timeline': parse_json_field(content.timeline),
        'achievements': parse_json_field(content.achievements),
        'amenities_section_title': content.amenities_section_title,
        'amenities_section_subtitle': content.amenities_section_subtitle,
        'amenities': parse_json_field(content.amenities),
        'testimonials_section_title': content.testimonials_section_title,
        'testimonials_section_subtitle': content.testimonials_section_subtitle,
        'testimonials': parse_json_field(content.testimonials),
        'gallery_section_title': content.gallery_section_title,
        'gallery_section_subtitle': content.gallery_section_subtitle,
        'gallery_images': parse_json_field(content.gallery_images),
        'luxury_section_title': content.luxury_section_title,
        'luxury_section_subtitle': content.luxury_section_subtitle,
        'luxury_section_image': content.luxury_section_image,
        'luxury_features': parse_json_field(content.luxury_features),
        'luxury_gallery_section_title': content.luxury_gallery_section_title,
        'luxury_gallery_section_subtitle': content.luxury_gallery_section_subtitle,
        'luxury_gallery': parse_json_field(content.luxury_gallery),
        'luxury_testimonials_section_title': content.luxury_testimonials_section_title,
        'luxury_testimonials_section_subtitle': content.luxury_testimonials_section_subtitle,
        'luxury_testimonials': parse_json_field(content.luxury_testimonials),
        'about_preview_title': content.about_preview_title,
        'about_preview_subtitle': content.about_preview_subtitle,
        'about_preview_content': content.about_preview_content,
        'about_preview_image': content.about_preview_image,
        'stats': parse_json_field(content.stats),
        'stats_section_title': content.stats_section_title,
        'stats_section_subtitle': content.stats_section_subtitle,
        'rooms_section_title': content.rooms_section_title,
        'rooms_section_subtitle': content.rooms_section_subtitle,
        'rooms_section_button_text': content.rooms_section_button_text,
        'rooms_section_button_link': content.rooms_section_button_link,
        'rooms_section_enabled': content.rooms_section_enabled,
        'luxury_services_section_title': content.luxury_services_section_title,
        'luxury_services_section_subtitle': content.luxury_services_section_subtitle,
        'services_section_button_text': content.services_section_button_text,
        'services_section_button_link': content.services_section_button_link,
        'services_section_limit': content.services_section_limit,
        'luxury_services': parse_json_field(content.luxury_services),
        'luxury_experiences_section_title': content.luxury_experiences_section_title,
        'luxury_experiences_section_subtitle': content.luxury_experiences_section_subtitle,
        'luxury_experiences': parse_json_field(content.luxury_experiences),
        'awards_section_title': content.awards_section_title,
        'awards_section_subtitle': content.awards_section_subtitle,
        'awards': parse_json_field(content.awards),
        'cta_title': content.cta_title,
        'cta_subtitle': content.cta_subtitle,
        'cta_button_text': content.cta_button_text,
        'cta_button_link': content.cta_button_link,
        'cta_image': content.cta_image,
        'partners_section_title': content.partners_section_title,
        'partners_section_subtitle': content.partners_section_subtitle,
        'partners': parse_json_field(content.partners),
        'sections_enabled': parse_json_field(content.sections_enabled),
        'newsletter_section_title': content.newsletter_section_title,
        'newsletter_section_subtitle': content.newsletter_section_subtitle,
        'newsletter_placeholder': content.newsletter_placeholder,
        'newsletter_button_text': content.newsletter_button_text,
        'newsletter_enabled': content.newsletter_enabled,
        'trust_badges_section_title': content.trust_badges_section_title,
        'trust_badges_section_subtitle': content.trust_badges_section_subtitle,
        'trust_badges': parse_json_field(content.trust_badges),
        'trust_badges_enabled': content.trust_badges_enabled,
        'promotions_section_title': content.promotions_section_title,
        'promotions_section_subtitle': content.promotions_section_subtitle,
        'promotions': parse_json_field(content.promotions),
        'promotions_enabled': content.promotions_enabled,
        'blog_section_title': content.blog_section_title,
        'blog_section_subtitle': content.blog_section_subtitle,
        'blog_posts_limit': content.blog_posts_limit,
        'blog_enabled': content.blog_enabled,
        'is_active': content.is_active,
        'created_at': content.created_at.isoformat() if content.created_at else None,
        'updated_at': content.updated_at.isoformat() if content.updated_at else None
    }

@router.get('/')
async def get_all_page_contents(db: Session=Depends(get_db)):
    try:
        contents = db.query(PageContent).all()
        result = []
        for content in contents:
            content_dict = build_content_dict(content)
            result.append(content_dict)
        return {'status': 'success', 'data': {'page_contents': result}}
    except Exception as e:
        db.rollback()
        logger.error(f'Error fetching page contents: {str(e)}', exc_info=True)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f'Error fetching page contents: {str(e)}')

def get_base_url(request: Request) -> str:
    return os.getenv('SERVER_URL') or f'http://{request.headers.get('host', 'localhost:8000')}'

def normalize_image_url(image_url: str, base_url: str) -> str:
    if not image_url:
        return image_url
    if image_url.startswith('http://') or image_url.startswith('https://'):
        return image_url
    if image_url.startswith('/'):
        return f'{base_url}{image_url}'
    return f'{base_url}/{image_url}'

@router.post('/upload', dependencies=[Depends(authorize_roles('admin'))])
async def upload_page_content_image(request: Request, image: UploadFile=File(...), current_user: User=Depends(authorize_roles('admin'))):
    try:
        logger.info(f'Upload request received: filename={image.filename}, content_type={image.content_type}')
        if not image:
            logger.error('No file provided in upload request')
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='No file provided')
        if not image.content_type or not image.content_type.startswith('image/'):
            logger.error(f'Invalid file type: {image.content_type}')
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f'File must be an image. Received: {image.content_type}')
        if not image.filename:
            logger.error('No filename provided in upload request')
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='Filename is required')
        upload_dir = Path(__file__).parent.parent.parent.parent / 'uploads' / 'page-content'
        upload_dir.mkdir(parents=True, exist_ok=True)
        logger.info(f'Upload directory: {upload_dir}')
        ext = Path(image.filename).suffix or '.jpg'
        filename = f'page-content-{uuid.uuid4()}{ext}'
        file_path = upload_dir / filename
        # Use comprehensive file validation (magic bytes + size)
        from ...shared.config.settings import settings
        from ...shared.utils.file_validation import validate_uploaded_image
        max_size = settings.MAX_UPLOAD_SIZE
        
        # Validate file completely (MIME type, size, magic bytes, integrity)
        content = await validate_uploaded_image(image, max_size)
        
        # Optimize image before saving
        from ...shared.utils.image_optimization import optimize_image_async, ImageType
        optimized_content, optimized_ext = await optimize_image_async(content, ImageType.PAGE_CONTENT)
        
        # Update filename extension if format changed
        if optimized_ext and optimized_ext != ext:
            filename = f'page-content-{uuid.uuid4()}{optimized_ext}'
            file_path = upload_dir / filename
        
        async with aiofiles.open(file_path, 'wb') as f:
            await f.write(optimized_content)
            logger.info(f'File saved successfully: {file_path}, size: {len(optimized_content)} bytes')
        image_url = f'/uploads/page-content/{filename}'
        base_url = get_base_url(request)
        full_url = normalize_image_url(image_url, base_url)
        logger.info(f'Upload successful: {image_url}')
        return {'success': True, 'status': 'success', 'message': 'Image uploaded successfully', 'data': {'image_url': image_url, 'full_url': full_url}}
    except HTTPException as e:
        logger.error(f'HTTPException in upload: {e.detail}')
        raise
    except Exception as e:
        logger.error(f'Unexpected error uploading image: {str(e)}', exc_info=True)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f'Error uploading image: {str(e)}')

@router.get('/{page_type}')
async def get_page_content(page_type: PageType, db: Session=Depends(get_db)):
    try:
        content = db.query(PageContent).filter(PageContent.page_type == page_type).first()
        if not content:
            return {'status': 'success', 'data': {'page_content': None}}
        content_dict = build_content_dict(content)
        return {'status': 'success', 'data': {'page_content': content_dict}}
    except Exception as e:
        db.rollback()
        logger.error(f'Error fetching page content: {str(e)}', exc_info=True)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f'Error fetching page content: {str(e)}')

@router.post('/{page_type}', dependencies=[Depends(authorize_roles('admin'))])
async def create_or_update_page_content(
    page_type: PageType,
    title: Optional[str] = None,
    subtitle: Optional[str] = None,
    description: Optional[str] = None,
    content: Optional[str] = None,
    meta_title: Optional[str] = None,
    meta_description: Optional[str] = None,
    meta_keywords: Optional[str] = None,
    og_title: Optional[str] = None,
    og_description: Optional[str] = None,
    og_image: Optional[str] = None,
    canonical_url: Optional[str] = None,
    contact_info: Optional[str] = None,
    map_url: Optional[str] = None,
    social_links: Optional[str] = None,
    footer_links: Optional[str] = None,
    badges: Optional[str] = None,
    hero_title: Optional[str] = None,
    hero_subtitle: Optional[str] = None,
    hero_image: Optional[str] = None,
    story_content: Optional[str] = None,
    values: Optional[str] = None,
    features: Optional[str] = None,
    about_hero_image: Optional[str] = None,
    mission: Optional[str] = None,
    vision: Optional[str] = None,
    team: Optional[str] = None,
    timeline: Optional[str] = None,
    achievements: Optional[str] = None,
    is_active: bool = True,
    current_user: User = Depends(authorize_roles('admin')),
    db: Session = Depends(get_db)
):
    try:
        if contact_info:
            try:
                json.loads(contact_info)
            except json.JSONDecodeError:
                raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='Invalid JSON in contact_info')
        if social_links:
            try:
                json.loads(social_links)
            except json.JSONDecodeError:
                raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='Invalid JSON in social_links')
        if footer_links:
            try:
                json.loads(footer_links)
            except json.JSONDecodeError:
                raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='Invalid JSON in footer_links')
        if badges:
            try:
                json.loads(badges)
            except json.JSONDecodeError:
                raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='Invalid JSON in badges')
        if values:
            try:
                json.loads(values)
            except json.JSONDecodeError:
                raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='Invalid JSON in values')
        if features:
            try:
                json.loads(features)
            except json.JSONDecodeError:
                raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='Invalid JSON in features')
        existing_content = db.query(PageContent).filter(PageContent.page_type == page_type).first()
        if existing_content:
            if title is not None:
                existing_content.title = sanitize_html(title)
            if subtitle is not None:
                existing_content.subtitle = sanitize_html(subtitle)
            if description is not None:
                existing_content.description = sanitize_html(description)
            if content is not None:
                # Sanitize HTML content to prevent XSS
                existing_content.content = sanitize_html(content)
            if meta_title is not None:
                existing_content.meta_title = meta_title
            if meta_description is not None:
                existing_content.meta_description = meta_description
            if meta_keywords is not None:
                existing_content.meta_keywords = meta_keywords
            if og_title is not None:
                existing_content.og_title = og_title
            if og_description is not None:
                existing_content.og_description = og_description
            if og_image is not None:
                existing_content.og_image = og_image
            if canonical_url is not None:
                existing_content.canonical_url = canonical_url
            if contact_info is not None:
                existing_content.contact_info = contact_info
            if map_url is not None:
                existing_content.map_url = map_url
            if social_links is not None:
                existing_content.social_links = social_links
            if footer_links is not None:
                existing_content.footer_links = footer_links
            if badges is not None:
                existing_content.badges = badges
            if hero_title is not None:
                existing_content.hero_title = sanitize_html(hero_title)
            if hero_subtitle is not None:
                existing_content.hero_subtitle = sanitize_html(hero_subtitle)
            if hero_image is not None:
                existing_content.hero_image = hero_image
            if story_content is not None:
                # Sanitize HTML content to prevent XSS
                existing_content.story_content = sanitize_html(story_content)
            if values is not None:
                existing_content.values = sanitize_html(values)
            if features is not None:
                existing_content.features = sanitize_html(features)
            if about_hero_image is not None:
                existing_content.about_hero_image = about_hero_image
            if mission is not None:
                existing_content.mission = sanitize_html(mission)
            if vision is not None:
                existing_content.vision = sanitize_html(vision)
            if team is not None:
                existing_content.team = sanitize_html(team)
            if timeline is not None:
                existing_content.timeline = sanitize_html(timeline)
            if achievements is not None:
                existing_content.achievements = sanitize_html(achievements)
            if is_active is not None:
                existing_content.is_active = is_active
            existing_content.updated_at = datetime.utcnow()
            db.commit()
            db.refresh(existing_content)
            return {'status': 'success', 'message': 'Page content updated successfully', 'data': {'page_content': {'id': existing_content.id, 'page_type': existing_content.page_type.value, 'title': existing_content.title, 'updated_at': existing_content.updated_at.isoformat() if existing_content.updated_at else None}}}
        else:
            # Sanitize all HTML content fields before creating new content
            new_content = PageContent(
                page_type=page_type, 
                title=sanitize_html(title) if title else None, 
                subtitle=sanitize_html(subtitle) if subtitle else None, 
                description=sanitize_html(description) if description else None, 
                content=sanitize_html(content) if content else None, 
                meta_title=meta_title, 
                meta_description=meta_description, 
                meta_keywords=meta_keywords, 
                og_title=og_title, 
                og_description=og_description, 
                og_image=og_image, 
                canonical_url=canonical_url, 
                contact_info=contact_info, 
                map_url=map_url, 
                social_links=social_links, 
                footer_links=footer_links, 
                badges=badges, 
                hero_title=sanitize_html(hero_title) if hero_title else None, 
                hero_subtitle=sanitize_html(hero_subtitle) if hero_subtitle else None, 
                hero_image=hero_image, 
                story_content=sanitize_html(story_content) if story_content else None, 
                values=sanitize_html(values) if values else None, 
                features=sanitize_html(features) if features else None, 
                about_hero_image=about_hero_image, 
                mission=sanitize_html(mission) if mission else None, 
                vision=sanitize_html(vision) if vision else None, 
                team=sanitize_html(team) if team else None, 
                timeline=sanitize_html(timeline) if timeline else None, 
                achievements=sanitize_html(achievements) if achievements else None, 
                is_active=is_active
            )
            db.add(new_content)
            db.commit()
            db.refresh(new_content)
            return {'status': 'success', 'message': 'Page content created successfully', 'data': {'page_content': {'id': new_content.id, 'page_type': new_content.page_type.value, 'title': new_content.title, 'created_at': new_content.created_at.isoformat() if new_content.created_at else None}}}
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f'Error saving page content: {str(e)}')

@router.put('/{page_type}')
async def update_page_content(page_type: PageType, page_data: PageContentUpdateRequest, current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
    try:
        authorize_roles(current_user, ['admin'])
        existing_content = db.query(PageContent).filter(PageContent.page_type == page_type).first()
        if not existing_content:
            existing_content = PageContent(page_type=page_type, is_active=True)
            db.add(existing_content)
        
        # Convert Pydantic model to dict, excluding None values
        update_dict = page_data.model_dump(exclude_unset=True, exclude_none=False)
        
        for key, value in update_dict.items():
            if hasattr(existing_content, key):
                # Convert dict/list to JSON string for JSON fields
                json_fields = ['contact_info', 'social_links', 'footer_links', 'badges', 'values', 'features', 'amenities', 'testimonials', 'gallery_images', 'stats', 'luxury_features', 'luxury_gallery', 'luxury_testimonials', 'luxury_services', 'luxury_experiences', 'awards', 'partners', 'team', 'timeline', 'achievements', 'sections_enabled', 'trust_badges', 'promotions']
                if key in json_fields and value is not None:
                    if isinstance(value, (dict, list)):
                        value = json.dumps(value)
                    elif isinstance(value, str):
                        # Already a JSON string, validate it
                        try:
                            json.loads(value)
                        except json.JSONDecodeError:
                            logger.warning(f'Invalid JSON string for field {key}, skipping')
                            continue
                # Handle empty arrays - set to None to avoid storing "[]"
                if isinstance(value, list) and len(value) == 0:
                    value = None
                if value is not None:
                    setattr(existing_content, key, value)
        existing_content.updated_at = datetime.utcnow()
        db.commit()
        db.refresh(existing_content)
        content_dict = build_content_dict(existing_content)
        return {'status': 'success', 'message': 'Page content updated successfully', 'data': {'page_content': content_dict}}
    except ValidationError as e:
        db.rollback()
        error_messages = []
        for error in e.errors():
            field = '.'.join(str(loc) for loc in error['loc'])
            error_messages.append(f"{field}: {error['msg']}")
        error_detail = 'Validation error: ' + '; '.join(error_messages)
        logger.error(f'Validation error updating page content ({page_type}): {error_detail}', exc_info=True)
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=error_detail)
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        logger.error(f'Error updating page content: {str(e)}', exc_info=True)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f'Error updating page content: {str(e)}')