#!/usr/bin/env python3
"""Shared fail-closed Postiz primitives for project-local schedulers and final audits."""

from __future__ import annotations

import json
import urllib.parse
import urllib.request
from collections import defaultdict
from typing import Any

from project_runtime import normalize_content, raw_postiz_headers

BASE_URL = "https://postiz-api.pain.io.vn/public/v1"


def request_json(method: str, route: str, api_key: str, payload: dict[str, Any] | None = None) -> Any:
    data = None if payload is None else json.dumps(payload).encode()
    request = urllib.request.Request(
        BASE_URL + route,
        data=data,
        headers=raw_postiz_headers(api_key),
        method=method,
    )
    with urllib.request.urlopen(request, timeout=180) as response:
        value = json.load(response)
    if isinstance(value, dict) and (value.get("error") is True or value.get("status") == "error"):
        raise RuntimeError("Postiz returned an error body")
    return value


def calendar(api_key: str, start_date: str, end_date: str) -> list[dict[str, Any]]:
    query = urllib.parse.urlencode({"startDate": start_date, "endDate": end_date})
    value = request_json("GET", f"/posts?{query}", api_key)
    posts = value.get("posts", value.get("data", value)) if isinstance(value, dict) else value
    if isinstance(posts, dict):
        posts = posts.get("posts", posts.get("data", []))
    if not isinstance(posts, list):
        raise ValueError("unexpected Calendar response")
    return posts


def integration_id(post: dict[str, Any]) -> str | None:
    nested = post.get("integration") or {}
    return nested.get("id") or post.get("integrationId")


def duplicate_groups(posts: list[dict[str, Any]]) -> list[dict[str, Any]]:
    groups: dict[tuple[str | None, str | None, str], list[str]] = defaultdict(list)
    for post in posts:
        content = post.get("content") or post.get("text") or ""
        groups[(integration_id(post), post.get("publishDate"), normalize_content(content))].append(post["id"])
    return [
        {"integration_id": key[0], "publish_date": key[1], "normalized_content": key[2], "ids": ids}
        for key, ids in groups.items()
        if len(ids) > 1
    ]


def exact_queue_readback(posts: list[dict[str, Any]], expected: dict[str, dict[str, str]]) -> dict[str, dict[str, Any]]:
    by_id = {post["id"]: post for post in posts}
    result = {}
    for post_id, contract in expected.items():
        post = by_id.get(post_id)
        if post is None:
            raise ValueError(f"missing exact Calendar ID: {post_id}")
        if post.get("state") != "QUEUE":
            raise ValueError(f"exact ID is not QUEUE: {post_id}")
        if integration_id(post) != contract["integration_id"]:
            raise ValueError(f"integration mismatch: {post_id}")
        if post.get("publishDate") != contract["publish_date"]:
            raise ValueError(f"publishDate mismatch: {post_id}")
        result[post_id] = post
    return result
