"""Background scheduler for handling scheduled posts.

This service runs in the background and:
1. Checks for posts that are due for publishing
2. Marks them as published
3. Sends notification emails to employees

Future extension: Could integrate with LinkedIn API for automatic posting.
"""
import asyncio
from datetime import datetime, timezone
from typing import Optional
from loguru import logger

from src.database.client import DatabaseClient
from src.services.email_service import send_email


class SchedulerService:
    """Background scheduler for post publishing."""

    def __init__(self, db: DatabaseClient, check_interval_seconds: int = 60):
        """Initialize the scheduler.

        Args:
            db: Database client instance
            check_interval_seconds: How often to check for due posts (default: 60s)
        """
        self.db = db
        self.check_interval = check_interval_seconds
        self._running = False
        self._task: Optional[asyncio.Task] = None

    async def start(self):
        """Start the background scheduler."""
        if self._running:
            logger.warning("Scheduler already running")
            return

        self._running = True
        self._task = asyncio.create_task(self._run_loop())
        logger.info(f"Scheduler started (checking every {self.check_interval}s)")

    async def stop(self):
        """Stop the background scheduler."""
        self._running = False
        if self._task:
            self._task.cancel()
            try:
                await self._task
            except asyncio.CancelledError:
                pass
        logger.info("Scheduler stopped")

    async def _run_loop(self):
        """Main scheduler loop."""
        _tick = 0
        while self._running:
            try:
                await self._process_due_posts()
            except Exception as e:
                logger.error(f"Scheduler error: {e}")

            # Daily jobs (every 1440 ticks = 24h at 60s interval)
            if _tick % 1440 == 0:
                try:
                    await self._refresh_expiring_tokens()
                except Exception as e:
                    logger.error(f"Token refresh job error: {e}")
                try:
                    await self.db.cleanup_expired_email_tokens()
                except Exception as e:
                    logger.error(f"Email token cleanup error: {e}")
                try:
                    from src.services.post_insights_service import refresh_all_post_insights
                    await refresh_all_post_insights(self.db)
                except Exception as e:
                    logger.error(f"Post insights daily job error: {e}")

            _tick += 1
            await asyncio.sleep(self.check_interval)

    async def _refresh_expiring_tokens(self):
        """Proactively refresh LinkedIn tokens expiring within 7 days."""
        from src.services.linkedin_service import linkedin_service
        accounts = await self.db.get_expiring_linkedin_accounts(within_days=7)
        if not accounts:
            return
        logger.info(f"Refreshing {len(accounts)} expiring LinkedIn tokens")
        for account in accounts:
            try:
                refreshed = await linkedin_service.refresh_access_token(account.id)
                if refreshed:
                    logger.info(f"Token refresh ok: {account.id}")
                else:
                    logger.warning(f"Token refresh failed: {account.id}")
            except Exception as e:
                logger.error(f"Token refresh error {account.id}: {e}")

    async def _process_due_posts(self):
        """Process all posts that are due for publishing."""
        due_posts = await self.db.get_scheduled_posts_due()

        if not due_posts:
            return

        logger.info(f"Processing {len(due_posts)} due posts")

        for post in due_posts:
            try:
                await self._publish_post(post)
            except Exception as e:
                logger.error(f"Failed to publish post {post.id}: {e}")

    async def _publish_post(self, post):
        """Publish a single post - with LinkedIn API if account linked, otherwise email."""
        from uuid import UUID

        # Get LinkedIn account for user
        linkedin_account = await self.db.get_linkedin_account(post.user_id)

        if linkedin_account:
            # User has LinkedIn account linked -> Try auto-posting
            try:
                await self._auto_post_to_linkedin(post, linkedin_account)
                return  # Success - no need for email fallback
            except Exception as e:
                logger.error(f"LinkedIn auto-post failed for post {post.id}: {e}")
                # Fall through to email notification

        # No LinkedIn account or auto-post failed -> Send email notification
        await self._publish_post_via_email(post)

    async def _auto_post_to_linkedin(self, post, linkedin_account):
        """Auto-post to LinkedIn using linked account."""
        from src.services.linkedin_service import linkedin_service
        from src.utils.encryption import decrypt_token

        # Check token expiry
        if linkedin_account.token_expires_at < datetime.now(timezone.utc):
            logger.warning(f"LinkedIn token expired for account {linkedin_account.id}")

            # Try to refresh token
            refreshed = await linkedin_service.refresh_access_token(linkedin_account.id)
            if not refreshed:
                # Token refresh failed -> Fall back to email
                raise Exception("Token expired and refresh failed")

        # Post to LinkedIn with media items
        # Convert media_items to dict if needed
        media_items_list = None
        if post.media_items:
            media_items_list = [
                item.dict() if hasattr(item, 'dict') else item
                for item in post.media_items
            ]

        result = await linkedin_service.post_to_linkedin(
            linkedin_account_id=linkedin_account.id,
            text=post.post_content,
            media_items=media_items_list,
            image_url=post.image_url  # Backward compatibility fallback
        )

        # Update post as published with LinkedIn metadata
        await self.db.update_generated_post(
            post.id,
            {
                "status": "published",
                "published_at": datetime.now(timezone.utc),
                "metadata": {
                    **(post.metadata or {}),
                    "linkedin_post_url": result.get("url"),
                    "auto_posted": True,
                    "posted_at": datetime.now(timezone.utc).isoformat()
                }
            }
        )

        logger.info(f"✅ Post {post.id} auto-posted to LinkedIn: {result.get('url')}")

        # Send success notification
        profile = await self.db.get_profile(post.user_id)
        if profile:
            await self._send_auto_post_success_notification(post, profile, result)

    async def _publish_post_via_email(self, post):
        """Fallback: Mark as published and send email notification."""
        # Update post status to published
        await self.db.update_generated_post(
            post.id,
            {
                "status": "published",
                "published_at": datetime.now(timezone.utc)
            }
        )

        logger.info(f"Post {post.id} marked as published (email notification)")

        # Get profile info for notification
        profile = await self.db.get_profile(post.user_id)
        if not profile:
            logger.warning(f"No profile found for post {post.id}")
            return

        # Send notification email
        await self._send_publish_notification(post, profile)

    async def _send_publish_notification(self, post, profile):
        """Send email notification that a post is ready to be published.

        Future: When LinkedIn API is integrated, this could instead
        confirm that the post was automatically published.
        """
        # Try to get employee email
        recipient_email = profile.creator_email or profile.customer_email
        if not recipient_email:
            logger.warning(f"No email for profile {profile.id}, skipping notification")
            return

        subject = "LinkedIn Post bereit zum Veröffentlichen"

        display_name = profile.display_name or "dort"

        # Generate media HTML
        media_html = ""
        if post.media_items and len(post.media_items) > 0:
            media_items = [item.dict() if hasattr(item, 'dict') else item for item in post.media_items]
            for item in sorted(media_items, key=lambda x: x.get('order', 0)):
                if item.get('type') == 'image':
                    media_html += f'<img src="{item["url"]}" alt="Post-Bild" style="width: 100%; max-height: 400px; object-fit: cover; border-radius: 8px; margin-top: 15px;" />'
                elif item.get('type') == 'video':
                    media_html += f'<video src="{item["url"]}" controls style="width: 100%; max-height: 400px; border-radius: 8px; margin-top: 15px;"></video>'
        elif post.image_url:
            # Backward compatibility
            media_html = f'<img src="{post.image_url}" alt="Post-Bild" style="width: 100%; max-height: 400px; object-fit: cover; border-radius: 8px; margin-top: 15px;" />'

        html_content = f"""
        <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
            <h2 style="color: #0a66c2;">Dein LinkedIn Post ist bereit! 🚀</h2>

            <p>Hallo {display_name},</p>

            <p>Dein geplanter LinkedIn Post ist jetzt zur Veröffentlichung bereit:</p>

            <div style="background: #f3f4f6; border-radius: 8px; padding: 20px; margin: 20px 0;">
                <p style="font-weight: bold; margin-bottom: 10px;">Thema: {post.topic_title}</p>
                <div style="background: white; border-radius: 4px; padding: 15px; white-space: pre-wrap; font-size: 14px; line-height: 1.5;">
{post.post_content[:500]}{'...' if len(post.post_content) > 500 else ''}
                </div>
                {media_html}
            </div>

            <p><strong>Nächste Schritte:</strong></p>
            <ol>
                <li>Öffne LinkedIn</li>
                <li>Erstelle einen neuen Post</li>
                <li>Kopiere den Text oben und füge ihn ein</li>
                <li>Veröffentliche den Post</li>
            </ol>

            <p style="color: #666; font-size: 12px; margin-top: 30px;">
                Diese Nachricht wurde automatisch generiert.
            </p>
        </div>
        """

        try:
            send_email(
                to_email=recipient_email,
                subject=subject,
                html_content=html_content
            )
            logger.info(f"Publish notification sent to {recipient_email}")
        except Exception as e:
            logger.error(f"Failed to send publish notification: {e}")

    async def _send_auto_post_success_notification(self, post, profile, result):
        """Send success email after auto-posting to LinkedIn."""
        recipient_email = profile.creator_email or profile.customer_email
        if not recipient_email:
            logger.warning(f"No email for profile {profile.id}, skipping success notification")
            return

        subject = "✅ LinkedIn Post automatisch veröffentlicht"
        display_name = profile.display_name or "dort"
        linkedin_url = result.get('url', 'https://www.linkedin.com/feed/')

        # Generate media HTML
        media_html = ""
        if post.media_items and len(post.media_items) > 0:
            media_items = [item.dict() if hasattr(item, 'dict') else item for item in post.media_items]
            for item in sorted(media_items, key=lambda x: x.get('order', 0)):
                if item.get('type') == 'image':
                    media_html += f'<img src="{item["url"]}" alt="Post-Bild" style="width: 100%; max-height: 400px; object-fit: cover; border-radius: 8px; margin-top: 15px;" />'
                elif item.get('type') == 'video':
                    media_html += f'<video src="{item["url"]}" controls style="width: 100%; max-height: 400px; border-radius: 8px; margin-top: 15px;"></video>'
        elif post.image_url:
            # Backward compatibility
            media_html = f'<img src="{post.image_url}" alt="Post-Bild" style="width: 100%; max-height: 400px; object-fit: cover; border-radius: 8px; margin-top: 15px;" />'

        html_content = f"""
        <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
            <h2 style="color: #0a66c2;">Post erfolgreich veröffentlicht! 🎉</h2>

            <p>Hallo {display_name},</p>

            <p>Dein geplanter LinkedIn Post wurde automatisch veröffentlicht:</p>

            <div style="background: #f3f4f6; border-radius: 8px; padding: 20px; margin: 20px 0;">
                <p style="font-weight: bold; margin-bottom: 10px;">Thema: {post.topic_title}</p>
                <div style="background: white; border-radius: 4px; padding: 15px; white-space: pre-wrap; font-size: 14px; line-height: 1.5;">
{post.post_content[:500]}{'...' if len(post.post_content) > 500 else ''}
                </div>
                {media_html}
            </div>

            <p>
                <a href="{linkedin_url}" style="display: inline-block; background: #0a66c2; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; font-weight: bold;">
                    Auf LinkedIn ansehen →
                </a>
            </p>

            <p style="color: #666; margin-top: 30px;">
                Dein Post wurde automatisch über dein verbundenes LinkedIn-Konto veröffentlicht.
            </p>

            <p style="color: #666; font-size: 12px; margin-top: 30px;">
                Diese Nachricht wurde automatisch generiert.
            </p>
        </div>
        """

        try:
            send_email(
                to_email=recipient_email,
                subject=subject,
                html_content=html_content
            )
            logger.info(f"Auto-post success notification sent to {recipient_email}")
        except Exception as e:
            logger.error(f"Failed to send success notification: {e}")


# Global scheduler instance
_scheduler: Optional[SchedulerService] = None


def get_scheduler() -> Optional[SchedulerService]:
    """Get the global scheduler instance."""
    return _scheduler


def init_scheduler(db: DatabaseClient, check_interval: int = 60) -> SchedulerService:
    """Initialize and return the global scheduler instance."""
    global _scheduler
    _scheduler = SchedulerService(db, check_interval)
    return _scheduler
