from __future__ import annotations

import json
from dataclasses import dataclass, field
from datetime import datetime, timezone
from pathlib import Path
from typing import Any

from .config import get_repository_metadata_dir


def _utc_now() -> str:
    return datetime.now(timezone.utc).isoformat()


def _safe_key(value: str) -> str:
    keep: list[str] = []
    for char in value:
        if char.isalnum() or char in {"-", "_"}:
            keep.append(char)
        else:
            keep.append("_")
    normalized = "".join(keep).strip("_")
    return normalized or "repository"


@dataclass(slots=True)
class RepositoryMetadataStore:
    base_dir: Path | None = None
    _dir: Path = field(init=False, repr=False)

    def __post_init__(self) -> None:
        self._dir = self.base_dir or get_repository_metadata_dir()
        self._dir.mkdir(parents=True, exist_ok=True)

    def put(self, repo_name: str, payload: dict[str, Any]) -> dict[str, Any]:
        now = _utc_now()
        existing = self.get(repo_name) or {}
        data = dict(existing)
        data.update(payload)
        data["repo_name"] = repo_name
        data["created_at"] = existing.get("created_at") or now
        data["updated_at"] = now
        self._path(repo_name).write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
        return data

    def get(self, repo_name: str) -> dict[str, Any] | None:
        path = self._path(repo_name)
        if not path.exists():
            return None
        try:
            payload = json.loads(path.read_text(encoding="utf-8"))
        except (OSError, json.JSONDecodeError):
            path.unlink(missing_ok=True)
            return None
        return payload if isinstance(payload, dict) else None

    def list(self) -> list[dict[str, Any]]:
        entries: list[dict[str, Any]] = []
        for path in sorted(self._dir.glob("*.json")):
            try:
                payload = json.loads(path.read_text(encoding="utf-8"))
            except (OSError, json.JSONDecodeError):
                continue
            if isinstance(payload, dict):
                entries.append(payload)
        entries.sort(key=lambda item: str(item.get("updated_at") or ""), reverse=True)
        return entries

    def _path(self, repo_name: str) -> Path:
        return self._dir / f"{_safe_key(repo_name)}.json"
