import logging
from datetime import datetime

from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.interval import IntervalTrigger

from backend.database.connection import SessionLocal
from backend.services import video_service
from backend.services.viral_detector import ViralDetector

logger = logging.getLogger("viral_social.scheduler")

scheduler = BackgroundScheduler()
detector = ViralDetector()

_job_log: list[dict] = []


def get_job_log() -> list[dict]:
    return list(reversed(_job_log[-50:]))


def _log(platform: str, status: str, message: str, count: int = 0):
    entry = {
        "timestamp": datetime.utcnow().isoformat(),
        "platform": platform,
        "status": status,
        "message": message,
        "count": count,
    }
    _job_log.append(entry)
    logger.info(f"[Scheduler] {platform}: {message}")


def discovery_job(region: str = "BR", max_per_platform: int = 50):
    """Master discovery job - uses ALL available sources."""
    from backend.services.discovery import ViralDiscovery
    db = SessionLocal()
    try:
        engine = ViralDiscovery()
        results = engine.discover_all(region=region, max_per_platform=max_per_platform)
        all_videos = results["youtube"] + results["tiktok"] + results["instagram"]
        if all_videos:
            saved = video_service.save_videos(db, all_videos)
            _log(
                "discovery", "success",
                f"{len(saved)} videos coletados de {len(results['sources_used'])} fontes: "
                f"YT={len(results['youtube'])}, TT={len(results['tiktok'])}, IG={len(results['instagram'])}",
                len(saved),
            )
        else:
            _log("discovery", "warning", "Nenhum video encontrado em nenhuma fonte")
    except Exception as e:
        _log("discovery", "error", str(e))
    finally:
        db.close()


def baseline_job():
    """Update creator baselines for outlier detection."""
    from backend.services.creator_baseline import CreatorBaselineService
    db = SessionLocal()
    try:
        svc = CreatorBaselineService()
        updated = svc.update_all_baselines(db)
        _log("baseline", "success", f"{updated} baselines atualizados", updated)
    except Exception as e:
        _log("baseline", "error", str(e))
    finally:
        db.close()


def growth_snapshot_job():
    """Take growth snapshots for recent videos."""
    from backend.services.growth_tracker import GrowthTracker
    db = SessionLocal()
    try:
        tracker = GrowthTracker()
        count = tracker.take_snapshots_for_recent(db, hours=72)
        _log("growth", "success", f"{count} snapshots registrados", count)
    except Exception as e:
        _log("growth", "error", str(e))
    finally:
        db.close()


def scrape_youtube_job(query: str = "", region: str = "BR", max_results: int = 25):
    from backend.scrapers.youtube import YouTubeScraper
    db = SessionLocal()
    try:
        scraper = YouTubeScraper()
        if query:
            videos_data = scraper.search_trending(query=query, region=region, max_results=max_results)
        else:
            videos_data = scraper.get_trending_videos(region=region, max_results=max_results)
        saved = video_service.save_videos(db, videos_data)
        _log("youtube", "success", f"{len(saved)} vídeos coletados", len(saved))
    except Exception as e:
        _log("youtube", "error", str(e))
    finally:
        db.close()


def scrape_tiktok_job(query: str = "", hashtag: str = "", max_results: int = 20):
    from backend.scrapers.tiktok import TikTokScraper
    db = SessionLocal()
    scraper = TikTokScraper()
    try:
        if hashtag:
            videos_data = scraper.get_hashtag_videos(hashtag, max_results)
        elif query:
            videos_data = scraper.search_videos(query, max_results)
        else:
            from backend.services.discovery import ViralDiscovery
            engine = ViralDiscovery()
            videos_data, sources = engine.discover_tiktok(max_results=max_results)
            if videos_data:
                saved = video_service.save_videos(db, videos_data)
                _log("tiktok", "success", f"{len(saved)} videos via discovery ({', '.join(sources)})", len(saved))
                return
            _log("tiktok", "skipped", "Sem query ou hashtag configurada")
            return
        saved = video_service.save_videos(db, videos_data)
        _log("tiktok", "success", f"{len(saved)} vídeos coletados", len(saved))
    except Exception as e:
        _log("tiktok", "error", str(e))
    finally:
        scraper.close()
        db.close()


def scrape_instagram_job(hashtag: str = "", username: str = "", max_results: int = 20):
    from backend.scrapers.instagram import InstagramScraper
    db = SessionLocal()
    scraper = InstagramScraper()
    try:
        if hashtag:
            videos_data = scraper.search_hashtag(hashtag, max_results)
        elif username:
            videos_data = scraper.get_user_reels(username, max_results)
        else:
            from backend.services.discovery import ViralDiscovery
            engine = ViralDiscovery()
            videos_data, sources = engine.discover_instagram(max_results=max_results)
            if videos_data:
                saved = video_service.save_videos(db, videos_data)
                _log("instagram", "success", f"{len(saved)} videos via discovery ({', '.join(sources)})", len(saved))
                return
            _log("instagram", "skipped", "Sem hashtag ou username configurado")
            return
        saved = video_service.save_videos(db, videos_data)
        _log("instagram", "success", f"{len(saved)} vídeos coletados", len(saved))
    except Exception as e:
        _log("instagram", "error", str(e))
    finally:
        scraper.close()
        db.close()


def _distribute_keywords_by_language(keywords: list[str], max_keywords: int) -> list[str]:
    """Distribute keywords - mixed PT-BR + EN for construction/luxury timelapse niche.

    Separates PT and EN keywords automatically and adds context suffixes.
    Distribution: 60% PT-BR, 40% EN (global reach for construction content).
    """
    import random

    # Context suffixes by language
    LANG_CONTEXT_PT = ["", " brasil", " br", " shorts"]
    LANG_CONTEXT_EN = ["", " shorts", " satisfying", " amazing"]

    # Auto-detect language: keywords with accents or PT words are Portuguese
    PT_MARKERS = {"construção", "mansão", "obra", "fundação", "acabamento", "casa ia", "reforma", "arquitetura", "luxo", "rápido", "sonhos", "padrão", "residencial", "moderno", "moderna", "do zero", "gerado"}

    pt_keywords = []
    en_keywords = []
    for kw in keywords:
        kw_lower = kw.lower()
        if any(marker in kw_lower for marker in PT_MARKERS):
            pt_keywords.append(kw)
        else:
            en_keywords.append(kw)

    total = min(len(keywords), max_keywords)
    if total == 0:
        return []

    # 60% PT, 40% EN
    pt_count = max(1, int(total * 0.6)) if pt_keywords else 0
    en_count = total - pt_count if en_keywords else 0
    # Adjust if one pool is empty
    if not pt_keywords:
        en_count = total
    if not en_keywords:
        pt_count = total

    result = []
    random.shuffle(pt_keywords)
    random.shuffle(en_keywords)

    for i in range(pt_count):
        kw = pt_keywords[i % len(pt_keywords)]
        suffix = random.choice(LANG_CONTEXT_PT)
        result.append(kw + suffix)

    for i in range(en_count):
        kw = en_keywords[i % len(en_keywords)]
        suffix = random.choice(LANG_CONTEXT_EN)
        result.append(kw + suffix)

    random.shuffle(result)
    return result


def scanner_auto_job():
    """Auto scanner job - runs on configured interval.

    Distributes keywords across languages: 50% PT, 30% EN, 20% ES.
    """
    from backend.models.settings import AppSettings
    db = SessionLocal()
    try:
        settings_rows = db.query(AppSettings).filter(AppSettings.category == "scanner").all()
        settings = {s.key: s.value for s in settings_rows}

        kw_str = settings.get("scanner_keywords", "")
        keywords = [k.strip() for k in kw_str.split(",") if k.strip()]

        if not keywords:
            _log("scanner", "skipped", "Nenhuma keyword configurada")
            return

        max_kw = int(settings.get("scanner_max_keywords_per_cycle", 3))
        distributed = _distribute_keywords_by_language(keywords, max_kw)

        from backend.services.viral_scanner import scan_keywords
        result = scan_keywords(distributed, settings)

        _log(
            "scanner", "success",
            f"{result.get('total_videos_saved', 0)} videos salvos, "
            f"{result.get('total_credits_used', 0)} creditos usados, "
            f"{result.get('videos_with_products', 0)} com produtos "
            f"(keywords: {', '.join(distributed[:5])})",
            result.get("total_videos_saved", 0),
        )

        # Auto-populate other sections from collected data (FREE)
        try:
            from backend.services.data_populator import populate_creators, populate_trends
            populate_creators(db)
            populate_trends(db)
        except Exception:
            pass

        # Shop auto-link removido - Apify e a fonte de dados TikTok Shop
    except Exception as e:
        _log("scanner", "error", str(e))
    finally:
        db.close()


    # shop_auto_scan_job removido - Apify e a fonte de dados TikTok Shop


def scanner_creative_center_job():
    """Creative Center auto discovery job (FREE)."""
    from backend.models.settings import AppSettings
    db = SessionLocal()
    try:
        settings_rows = db.query(AppSettings).filter(AppSettings.category == "scanner").all()
        settings = {s.key: s.value for s in settings_rows}

        from backend.services.viral_scanner import scan_with_creative_center
        result = scan_with_creative_center(settings)

        _log(
            "scanner_cc", "success",
            f"Creative Center: {result.get('trending_found', 0)} trends, "
            f"{result.get('total_videos_saved', 0)} videos salvos",
            result.get("total_videos_saved", 0),
        )
    except Exception as e:
        _log("scanner_cc", "error", str(e))
    finally:
        db.close()


def trends_scanner_auto_job():
    """Auto trends scanner job - fetches trending TikTok + YouTube Shorts."""
    from backend.models.settings import AppSettings
    db = SessionLocal()
    try:
        settings_rows = db.query(AppSettings).filter(
            AppSettings.category.in_(["scanner", "trends"])
        ).all()
        settings = {s.key: s.value for s in settings_rows}

        from backend.services.trends_scanner import scan_trends
        result = scan_trends(settings)

        _log(
            "trends_scanner", "success",
            f"TikTok={result.get('tiktok_found', 0)}, "
            f"YouTube={result.get('youtube_found', 0)}, "
            f"{result.get('total_videos_saved', 0)} salvos, "
            f"{result.get('total_credits_used', 0)} creditos",
            result.get("total_videos_saved", 0),
        )

        # Auto-populate
        try:
            from backend.services.data_populator import populate_creators, populate_trends
            populate_creators(db)
            populate_trends(db)
        except Exception:
            pass
    except Exception as e:
        _log("trends_scanner", "error", str(e))
    finally:
        db.close()


def tiktok_shop_sync_job():
    """Sync TikTok Shop data via Apify to local cache.

    Searches popular keywords and caches product/seller data.
    Also takes snapshots for monitored products (trend tracking).
    Cost: ~$0.15 per keyword (10 products each).
    """
    from backend.core.config import settings as app_settings
    from backend.models.settings import AppSettings
    db = SessionLocal()
    try:
        token = app_settings.APIFY_API_TOKEN
        if not token:
            row = db.query(AppSettings).filter(AppSettings.key == "apify_api_token").first()
            token = row.value if row else ""
        if not token:
            _log("tiktok_shop", "skipped", "APIFY_API_TOKEN nao configurado")
            return

        # Get custom keywords from settings
        kw_row = db.query(AppSettings).filter(AppSettings.key == "shop_sync_keywords").first()
        keywords = None
        if kw_row and kw_row.value:
            keywords = [k.strip() for k in kw_row.value.split(",") if k.strip()]

        from backend.services.tiktok_shop_cache import TikTokShopCacheService
        svc = TikTokShopCacheService(token)
        count = svc.sync_rankings(keywords)
        svc.clear_expired()
        _log("tiktok_shop", "success",
             f"{count} keywords sincronizados, snapshots atualizados", count)
    except Exception as e:
        _log("tiktok_shop", "error", str(e))
    finally:
        db.close()


# ── Schedule config stored in memory (persists during server lifetime) ──
_schedule_config: dict = {
    "enabled": False,
    "interval_hours": 6,
    "youtube": {"enabled": True, "query": "", "region": "BR", "max_results": 25},
    "tiktok": {"enabled": False, "query": "", "hashtag": "", "max_results": 20},
    "instagram": {"enabled": False, "hashtag": "", "username": "", "max_results": 20},
    "scanner": {"enabled": False, "interval_minutes": 30, "creative_center_enabled": True, "creative_center_interval_minutes": 60},
    "trends_scanner": {"enabled": False, "interval_minutes": 15},
    "shop": {"enabled": False, "interval_hours": 6},
}


def get_schedule_config() -> dict:
    return {**_schedule_config, "running": scheduler.running, "jobs": len(scheduler.get_jobs())}


def update_schedule(config: dict):
    global _schedule_config
    _schedule_config.update(config)

    # Remove existing jobs
    for job in scheduler.get_jobs():
        job.remove()

    if not _schedule_config.get("enabled"):
        _log("scheduler", "info", "Agendamento desativado")
        return

    hours = _schedule_config.get("interval_hours", 6)
    trigger = IntervalTrigger(hours=hours)

    yt = _schedule_config.get("youtube", {})
    if yt.get("enabled"):
        scheduler.add_job(
            scrape_youtube_job, trigger,
            kwargs={"query": yt.get("query", ""), "region": yt.get("region", "BR"), "max_results": yt.get("max_results", 25)},
            id="youtube_scrape", replace_existing=True,
        )

    tt = _schedule_config.get("tiktok", {})
    if tt.get("enabled"):
        scheduler.add_job(
            scrape_tiktok_job, trigger,
            kwargs={"query": tt.get("query", ""), "hashtag": tt.get("hashtag", ""), "max_results": tt.get("max_results", 20)},
            id="tiktok_scrape", replace_existing=True,
        )

    ig = _schedule_config.get("instagram", {})
    if ig.get("enabled"):
        scheduler.add_job(
            scrape_instagram_job, trigger,
            kwargs={"hashtag": ig.get("hashtag", ""), "username": ig.get("username", ""), "max_results": ig.get("max_results", 20)},
            id="instagram_scrape", replace_existing=True,
        )

    # Scanner jobs
    scanner = _schedule_config.get("scanner", {})
    if scanner.get("enabled"):
        scanner_minutes = scanner.get("interval_minutes", 30)
        scanner_trigger = IntervalTrigger(minutes=scanner_minutes)
        scheduler.add_job(
            scanner_auto_job, scanner_trigger,
            id="scanner_auto", replace_existing=True,
        )

        if scanner.get("creative_center_enabled", True):
            cc_minutes = scanner.get("creative_center_interval_minutes", 60)
            cc_trigger = IntervalTrigger(minutes=cc_minutes)
            scheduler.add_job(
                scanner_creative_center_job, cc_trigger,
                id="scanner_creative_center", replace_existing=True,
            )

    # Trends Scanner jobs
    trends = _schedule_config.get("trends_scanner", {})
    if trends.get("enabled"):
        trends_minutes = trends.get("interval_minutes", 15)
        trends_trigger = IntervalTrigger(minutes=trends_minutes)
        scheduler.add_job(
            trends_scanner_auto_job, trends_trigger,
            id="trends_scanner_auto", replace_existing=True,
        )

    # TikTok Shop sync via Apify - every 12 hours (cost: ~$0.15/keyword)
    scheduler.add_job(
        tiktok_shop_sync_job, IntervalTrigger(hours=12),
        id="tiktok_shop_sync", replace_existing=True,
    )

    _log("scheduler", "info", f"Agendamento ativado: a cada {hours}h, {len(scheduler.get_jobs())} jobs")


def load_settings_from_db():
    """Load scanner/scheduler/shop settings from DB and activate jobs on startup."""
    from backend.models.settings import AppSettings
    db = SessionLocal()
    try:
        rows = db.query(AppSettings).filter(AppSettings.category.in_(["scanner", "shop", "trends"])).all()
        settings = {r.key: r.value for r in rows}

        scanner_enabled = settings.get("scanner_enabled", "false").lower() == "true"
        cc_enabled = settings.get("scanner_creative_center_enabled", "true").lower() == "true"
        scanner_minutes = int(settings.get("scanner_interval_minutes", "30"))
        cc_minutes = int(settings.get("scanner_creative_center_interval_minutes", "60"))

        shop_enabled = settings.get("shop_auto_detect_enabled", "false").lower() == "true"
        shop_hours = int(settings.get("shop_auto_detect_interval_hours", "6"))

        trends_enabled = settings.get("trends_scanner_enabled", "false").lower() == "true"
        trends_minutes = int(settings.get("trends_scanner_interval_minutes", "15"))

        config = {
            "enabled": True,
            "interval_hours": 6,
            "youtube": {"enabled": False, "query": "", "region": "BR", "max_results": 25},
            "tiktok": {"enabled": False, "query": "", "hashtag": "", "max_results": 20},
            "instagram": {"enabled": False, "hashtag": "", "username": "", "max_results": 20},
            "scanner": {
                "enabled": scanner_enabled,
                "interval_minutes": scanner_minutes,
                "creative_center_enabled": cc_enabled,
                "creative_center_interval_minutes": cc_minutes,
            },
            "trends_scanner": {
                "enabled": trends_enabled,
                "interval_minutes": trends_minutes,
            },
            "shop": {
                "enabled": shop_enabled,
                "interval_hours": shop_hours,
            },
        }

        update_schedule(config)
        _log("scheduler", "info",
             f"Configuracoes carregadas do banco: scanner={'ON' if scanner_enabled else 'OFF'}, "
             f"creative_center={'ON' if cc_enabled else 'OFF'}, "
             f"shop={'ON' if shop_enabled else 'OFF'} (a cada {shop_hours}h), "
             f"trends={'ON' if trends_enabled else 'OFF'} (a cada {trends_minutes}min), "
             f"intervalo={scanner_minutes}min, cc_intervalo={cc_minutes}min")

        # TikTok Shop sync via Apify will run via scheduler every 12h
        # No startup sync to avoid burning API quota on restarts
    except Exception as e:
        _log("scheduler", "error", f"Erro ao carregar configuracoes do banco: {e}")
    finally:
        db.close()


def shop_accounts_refresh_job():
    """Refresh all TikTok Shop monitored accounts every 6h."""
    db = SessionLocal()
    try:
        from backend.services.tiktok_shop_monitor import refresh_all_accounts
        result = refresh_all_accounts(db)
        _log(
            "shop_accounts", "success",
            f"Shop accounts refresh: {result['success']}/{result['total']} ok, {result['errors']} erros",
            result["success"],
        )
    except Exception as e:
        _log("shop_accounts", "error", str(e))
    finally:
        db.close()


def youtube_upload_processor_job():
    """Process pending YouTube uploads every 60s."""
    try:
        from backend.services.youtube_uploader import youtube_upload_service
        youtube_upload_service.process_next_upload()
    except Exception as e:
        _log("youtube_upload", "error", str(e))


def start_scheduler():
    if not scheduler.running:
        scheduler.start()
        # Always-on: YouTube upload processor every 60 seconds
        scheduler.add_job(
            youtube_upload_processor_job,
            IntervalTrigger(seconds=60),
            id="youtube_upload_processor",
            replace_existing=True,
        )
        # Always-on: TikTok Shop accounts refresh every 6 hours
        scheduler.add_job(
            shop_accounts_refresh_job,
            IntervalTrigger(hours=6),
            id="shop_accounts_refresh",
            replace_existing=True,
        )
        _log("scheduler", "info", "Scheduler iniciado")


def stop_scheduler():
    if scheduler.running:
        scheduler.shutdown(wait=False)
        _log("scheduler", "info", "Scheduler parado")
