from __future__ import annotations

import asyncio
import time
import logging

from config import settings
from database.db import init_db
from database.manager import DatabaseManager
from agents.parser_agent import FlashscoreParser
from agents.predictor_agent import PredictorAgent
from agents.analyzer_agent import AnalyzerAgent
from analytics.metrics import compute_metrics

log = logging.getLogger("core.worker")
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
)

async def worker_loop():
    await init_db()

    db = DatabaseManager()
    parser = FlashscoreParser()
    predictor = PredictorAgent(db)
    analyzer = AnalyzerAgent(db)

    last_upcoming = 0.0
    last_live = 0.0
    last_metrics = 0.0
    last_strengths = 0.0

    competition_urls = settings.competition_urls()
    if not competition_urls:
        raise RuntimeError("No FLASHSCORE_COMPETITION_URLS configured")

    log.info("Worker started. competitions=%d", len(competition_urls))

    while True:
        now = time.time()

        # 1️⃣ Парсинг предстоящих матчей
        if now - last_upcoming >= settings.REFRESH_UPCOMING_EVERY_S:
            last_upcoming = now
            for cu in competition_urls:
                try:
                    matches = await parser.fetch_competition_matches(cu)
                    for m in matches[:250]:
                        await db.upsert_match(m)
                    log.info("Synced %d matches from %s", len(matches), cu)
                except Exception as e:
                    log.exception("Competition fetch failed for %s: %s", cu, e)

        # 2️⃣ Обновление live / finished
        if now - last_live >= settings.REFRESH_LIVE_EVERY_S:
            last_live = now
            try:
                live_matches = await db.list_matches(status="live", limit=120)
                candidates = live_matches + await db.list_matches(status="scheduled", limit=40)

                for m in candidates:
                    if not m.match_url:
                        continue

                    upd = await parser.fetch_match_detail_update(m.match_url)

                    merged = {
                        "id": m.id,
                        "source": "flashscore",
                        "competition_url": m.competition_url,
                        "match_url": m.match_url,
                        "kickoff_ts": m.kickoff_ts,
                        "home_team": m.home_team,
                        "away_team": m.away_team,
                        "status": upd.get("status", m.status),
                        "minute": upd.get("minute", m.minute),
                        "home_score": upd.get("home_score", m.home_score),
                        "away_score": upd.get("away_score", m.away_score),
                    }
                    await db.upsert_match(merged)

                if candidates:
                    log.info("Live refresh candidates=%d", len(candidates))
            except Exception as e:
                log.exception("Live refresh failed: %s", e)

        # 3️⃣ 🔥 ПЕРЕСЧЁТ СИЛЫ КОМАНД (КАЖДЫЕ 10 МИН)
        if now - last_strengths >= 600:
            last_strengths = now
            try:
                await analyzer.recompute_team_strengths()
                log.info("Team strengths recomputed")
            except Exception as e:
                log.exception("Team strength recompute failed: %s", e)

        # 4️⃣ Прогнозы
        try:
            targets = (
                await db.list_matches(status="scheduled", limit=80)
                + await db.list_matches(status="live", limit=80)
            )
            for m in targets:
                pr = await predictor.predict_for_match(m)
                await db.upsert_prediction(pr)

            if targets:
                log.info("Predictions updated for %d matches", len(targets))
        except Exception as e:
            log.exception("Prediction update failed: %s", e)

        # 5️⃣ Метрики
        if now - last_metrics >= 900:
            last_metrics = now
            try:
                met = await compute_metrics(db, model="poisson+strength")
                await db.save_metrics(
                    model="poisson+strength",
                    n=met["n_matches"],
                    acc=met["accuracy"],
                    brier=met["brier"],
                    logloss=met["logloss"],
                )
                log.info(
                    "Metrics updated: n=%d acc=%.3f brier=%.3f ll=%.3f",
                    met["n_matches"],
                    met["accuracy"],
                    met["brier"],
                    met["logloss"],
                )
            except Exception as e:
                log.exception("Metrics compute failed: %s", e)

        await asyncio.sleep(settings.LOOP_TICK_S)

def main():
    asyncio.run(worker_loop())

if __name__ == "__main__":
    main()
