import json
from datetime import timedelta, datetime as dt
import logging
from sqlalchemy import select, func

from .db import AsyncSessionLocal
from .services.slack_publisher import publish
from .model_defs import l2a_models, c2a_models
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from .models import SlackPrefs
from .cron.insight_detector_jobs import (
    auto_reopen_tickets,
    auto_resolve_tickets,
    detect_error_first_seen,
    detect_error_rate_regression,
)

log = logging.getLogger(__name__)


def start_digest_scheduler():
    try:
        sched = AsyncIOScheduler()
        # Run hourly on the hour; filtering per-tenant inside the job
        sched.add_job(send_weekly_digest, "cron", minute=0, id="weekly_digest_hourly")
        # Autofill daemon: run every 5 minutes
        try:
            from .services.autofill_daemon import tick_once as autofill_tick

            sched.add_job(autofill_tick, "cron", minute="*/5", id="autofill_tick")
        except Exception:
            log.exception("Failed to schedule autofill daemon")
        sched.start()
        log.info("Weekly digest scheduler started")
    except Exception:
        log.exception("Failed to start digest scheduler")


def start_insight_detector_scheduler():
    """Optional APScheduler fallback for insight detectors (15 min cadence)."""
    try:
        sched = AsyncIOScheduler()
        sched.add_job(
            run_insight_detectors,
            "cron",
            minute="*/15",
            id="insight_detectors",
        )
        sched.start()
        log.info("Insight detector scheduler started")
    except Exception:
        log.exception("Failed to start insight detector scheduler")


async def run_insight_detectors():
    async with AsyncSessionLocal() as db:
        await detect_error_first_seen(db)
        await detect_error_rate_regression(db)
        await auto_resolve_tickets(db)
        await auto_reopen_tickets(db)


async def send_weekly_digest():
    now = dt.utcnow()
    weekday = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"][now.weekday()]
    hour = now.hour
    window = now - timedelta(days=7)
    async with AsyncSessionLocal() as db:
        # Find accounts whose prefs match this UTC day/hour and are enabled
        try:
            acc_rows = (
                await db.execute(
                    select(SlackPrefs.account_id).where(
                        SlackPrefs.digest_enabled == True,  # noqa: E712
                        SlackPrefs.digest_day == weekday,
                        SlackPrefs.digest_hour_utc == hour,
                    )
                )
            ).all()
        except Exception:
            acc_rows = []
        accs = [str(r[0]) for r in acc_rows if r and r[0]]
        for acc in accs:
            try:
                blocks = await _build_digest_blocks(db, acc, window=window)
                if blocks:
                    await publish("digest", acc, blocks)
            except Exception:
                log.exception("digest failed for %s", acc)


async def _build_digest_blocks(db, account_id: str, window):
    try:
        l2a_count = (
            await db.execute(
                select(func.count())
                .select_from(l2a_models.L2ABulkJob)
                .where(
                    l2a_models.L2ABulkJob.account_id == account_id,
                    l2a_models.L2ABulkJob.updated_at >= window,
                )
            )
        ).scalar_one()
    except Exception:
        l2a_count = 0
    try:
        c2a_count = (
            await db.execute(
                select(func.count())
                .select_from(c2a_models.C2AJob)
                .where(
                    c2a_models.C2AJob.account_id == account_id,
                    c2a_models.C2AJob.updated_at >= window,
                )
            )
        ).scalar_one()
    except Exception:
        c2a_count = 0

    blocks = [
        {
            "type": "section",
            "text": {"type": "mrkdwn", "text": "*FoundryOps Weekly Digest*"},
        },
        {
            "type": "context",
            "elements": [
                {
                    "type": "mrkdwn",
                    "text": f"L2A jobs: *{l2a_count}* • C2A jobs: *{c2a_count}* (last 7 days)",
                }
            ],
        },
        {"type": "divider"},
    ]

    # Prefer per-tenant threshold when available
    try:
        prefs = (
            await db.execute(
                select(SlackPrefs).where(SlackPrefs.account_id == account_id).limit(1)
            )
        ).scalar_one_or_none()
        min_score = float(getattr(prefs, "c2a_safe_threshold", None) or 0.8)
    except Exception:
        min_score = 0.8
    min_pct = int(min_score * 100)
    blocks.append(
        {
            "type": "section",
            "text": {
                "type": "mrkdwn",
                "text": f"Approve safe C2A matches (≥ *{min_pct}%*)",
            },
            "accessory": {
                "type": "button",
                "style": "primary",
                "text": {"type": "plain_text", "text": "Approve-Safe"},
                "action_id": "approve",
                "value": json.dumps(
                    {"type": "c2a", "op": "approve_safe", "min_score": min_score}
                ),
            },
        }
    )

    return {"blocks": blocks}
