from __future__ import annotations

import json
from typing import Any, Dict, Mapping

from .types import to_plain


def _is_object(value: Any) -> bool:
    return isinstance(value, Mapping)


def _sort_keys_deep(value: Any) -> Any:
    if isinstance(value, list):
        return [_sort_keys_deep(item) for item in value]

    if not _is_object(value):
        return value

    sorted_obj: Dict[str, Any] = {}
    for key in sorted(value.keys()):
        sorted_obj[str(key)] = _sort_keys_deep(value[key])
    return sorted_obj


def canonicalize(value: Any) -> str:
    normalized = to_plain(value)
    return json.dumps(_sort_keys_deep(normalized), ensure_ascii=False, separators=(",", ":"))


def _to_signable_receipt(receipt: Any) -> Dict[str, Any]:
    clone_json = json.dumps(to_plain(receipt), ensure_ascii=False, separators=(",", ":"))
    clone_obj = json.loads(clone_json)

    signature = clone_obj.get("signature") if isinstance(clone_obj, dict) else None
    if not isinstance(signature, dict):
        raise ValueError("Invalid receipt.signature")

    signature.pop("sig", None)
    clone_obj["signature"] = signature
    return clone_obj


def canonicalize_for_signing(receipt: Any) -> str:
    return canonicalize(_to_signable_receipt(receipt))


canonicalizeForSigning = canonicalize_for_signing

__all__ = ["canonicalize", "canonicalize_for_signing", "canonicalizeForSigning"]
