import re
import os
import json
from typing import Type, TypeVar
from pydantic import BaseModel
from guayaba.app import output
from dataclasses import asdict, is_dataclass
from pydantic.type_adapter import TypeAdapter


T = TypeVar("T", bound=BaseModel)


def base_path_for_post(path: str) -> str:
    suffix_match = re.search(r"/{\w+}$", path)
    return path[:suffix_match.start()] if suffix_match else path


def save(data: object, path: str) -> None:
    """Save any class instance (preferably Pydantic model) or a string to a file."""
    outpath = output / path
    os.makedirs(outpath.parent, exist_ok=True)
    with open(outpath, "w", encoding="utf-8") as f:
        if isinstance(data, BaseModel):
            f.write(data.model_dump_json(indent=4))
        elif is_dataclass(data):
            json.dump(asdict(data), f, indent=4)
        else:
            f.write(str(data))


def load(path: str, model: Type[T] | None = None) -> T | str | None:
    """
    Load a file. If `model` is provided, parse JSON into that Pydantic model.
    Returns:
        - model instance if `model` provided
        - raw string otherwise
        - None if file not found
    """
    try:
        with open(path, "r", encoding="utf-8") as f:
            content = f.read()
            if model:
                if isinstance(model, type) and issubclass(model, BaseModel):
                    return model.model_validate_json(content)
                if is_dataclass(model):
                    adapter = TypeAdapter(model)
                    return adapter.validate_json(content)
                return TypeAdapter(model).validate_json(content)
            return content
    except FileNotFoundError:
        return None
    
    