"""Idempotency-Key header handling for API v1 writes."""

from __future__ import annotations

import hashlib
import json
import logging
from datetime import datetime, timedelta
from typing import Any, Optional, Tuple

from flask import Response, jsonify

from app import db
from app.models.api_idempotency_key import ApiIdempotencyKey
from app.utils.db import safe_commit

logger = logging.getLogger(__name__)

IDEMPOTENCY_TTL_HOURS = 24
MAX_KEY_LEN = 128
SCOPE_POST_TIME_ENTRY = "post:time_entries"


def _hash_key(raw: str) -> str:
    return hashlib.sha256(raw.encode("utf-8")).hexdigest()


def normalize_idempotency_key(header_value: Optional[str]) -> Optional[str]:
    if not header_value or not isinstance(header_value, str):
        return None
    s = header_value.strip()
    if not s or len(s) > MAX_KEY_LEN:
        return None
    return s


def lookup_idempotent_response(api_token_id: int, scope: str, key: str) -> Optional[Tuple[int, str]]:
    row = ApiIdempotencyKey.query.filter_by(
        api_token_id=api_token_id,
        scope=scope,
        key_hash=_hash_key(key),
    ).first()
    if not row:
        return None
    cutoff = datetime.utcnow() - timedelta(hours=IDEMPOTENCY_TTL_HOURS)
    if row.created_at < cutoff:
        try:
            db.session.delete(row)
            safe_commit("idempotency_expired_cleanup", {})
        except Exception as e:
            logger.debug("Idempotency cleanup: %s", e)
        return None
    return row.response_status, row.response_body


def store_idempotent_response(api_token_id: int, scope: str, key: str, status_code: int, body_dict: Any) -> None:
    body_json = json.dumps(body_dict, default=str)
    row = ApiIdempotencyKey(
        api_token_id=api_token_id,
        scope=scope,
        key_hash=_hash_key(key),
        response_status=status_code,
        response_body=body_json,
    )
    db.session.add(row)
    if not safe_commit("api_idempotency_store", {"scope": scope}):
        logger.warning("Failed to store idempotency key for token %s", api_token_id)


def replay_response(status_code: int, body_json: str) -> Response:
    try:
        data = json.loads(body_json)
    except Exception:
        data = {"message": body_json}
    resp = jsonify(data)
    resp.status_code = status_code
    return resp
