import json
import os
import fcntl
import tempfile
from pathlib import Path
from datetime import datetime, timezone

class StateStore:
    def __init__(self, ruta):
        self.path = Path(ruta)
        self.lock_path = Path(str(ruta) + ".lock")

    def leer(self):
        if not self.path.exists():
            return {"games": {}}

        try:
            data = json.loads(
                self.path.read_text(encoding="utf-8")
            )
            if not isinstance(data.get("games"), dict):
                return {"games": {}}
            return data
        except (OSError, ValueError, TypeError):
            return {"games": {}}

    def guardar(self, data):
        self.path.parent.mkdir(
            parents=True, exist_ok=True
        )

        with open(self.lock_path, "a+") as lock:
            fcntl.flock(lock, fcntl.LOCK_EX)

            fd, temporal = tempfile.mkstemp(
                dir=str(self.path.parent),
                prefix=self.path.name + "."
            )

            try:
                data["updated_at"] = (
                    datetime.now(timezone.utc).isoformat()
                )

                with os.fdopen(fd, "w", encoding="utf-8") as f:
                    json.dump(data, f, indent=2)
                    f.flush()
                    os.fsync(f.fileno())

                os.replace(temporal, self.path)

            finally:
                if os.path.exists(temporal):
                    os.unlink(temporal)

                fcntl.flock(lock, fcntl.LOCK_UN)

    def actualizar(self, funcion):
        self.path.parent.mkdir(
            parents=True, exist_ok=True
        )

        with open(self.lock_path, "a+") as lock:
            fcntl.flock(lock, fcntl.LOCK_EX)

            try:
                if self.path.exists():
                    data = json.loads(
                        self.path.read_text(encoding="utf-8")
                    )

                    if not isinstance(data, dict):
                        raise ValueError("Estado invalido")

                    if not isinstance(data.get("games"), dict):
                        raise ValueError("Games invalido")
                else:
                    data = {"games": {}}

                resultado = funcion(data)

                if not isinstance(data.get("games"), dict):
                    raise ValueError("Games invalido tras actualizar")

                data["updated_at"] = (
                    datetime.now(timezone.utc).isoformat()
                )

                fd, temporal = tempfile.mkstemp(
                    dir=str(self.path.parent),
                    prefix=self.path.name + "."
                )

                try:
                    with os.fdopen(fd, "w", encoding="utf-8") as f:
                        json.dump(data, f, indent=2)
                        f.flush()
                        os.fsync(f.fileno())

                    os.replace(temporal, self.path)

                finally:
                    if os.path.exists(temporal):
                        os.unlink(temporal)

                return resultado

            finally:
                fcntl.flock(lock, fcntl.LOCK_UN)
