"""Webhook receiver — routes incoming webhooks to matching jobs."""

import structlog
from fastapi import APIRouter, Request

from fliiq.runtime.scheduler.executor import execute_job
from fliiq.runtime.scheduler.loader import load_jobs

log = structlog.get_logger()

router = APIRouter(prefix="/api/webhooks")


def _resolve_dotpath(data: dict, key: str):
    """Resolve a dot-notation key path in a nested dict. Returns None on miss."""
    parts = key.split(".")
    current = data
    for part in parts:
        if isinstance(current, dict) and part in current:
            current = current[part]
        else:
            return None
    return current


def _matches(match_config: dict[str, str] | None, payload: dict) -> bool:
    """Check if payload matches all key-value pairs in match_config (AND logic)."""
    if not match_config:
        return True
    for key, expected in match_config.items():
        actual = _resolve_dotpath(payload, key)
        if str(actual) != str(expected):
            return False
    return True


@router.post("/{source}")
async def receive_webhook(source: str, request: Request):
    """Receive a webhook and fire matching jobs."""
    try:
        payload = await request.json()
    except Exception:
        payload = {}

    jobs_dir = request.app.state.jobs_dir
    project_root = request.app.state.project_root
    llm_config = request.app.state.llm_config

    all_jobs = load_jobs(jobs_dir)
    matched_jobs = [
        j for j in all_jobs
        if j.enabled
        and j.trigger.type == "webhook"
        and j.trigger.source == source
        and _matches(j.trigger.match, payload)
    ]

    results = []
    for job in matched_jobs:
        log.info("webhook_firing_job", source=source, job=job.name)
        try:
            entry = await execute_job(job, jobs_dir, project_root, llm_config, payload=payload)
            results.append({"job": job.name, "status": entry.status})
        except Exception as e:
            log.error("webhook_job_failed", job=job.name, error=str(e))
            results.append({"job": job.name, "status": "error", "error": str(e)})

    return {"matched": len(matched_jobs), "results": results}
