"""
Global helper functions (equivalent to Laravel's global helpers).

Import from caprail.support.helpers or use via ``from caprail import *``.
"""
from __future__ import annotations

import os
from pathlib import Path
from typing import Any

# These are set by the Application on boot
_app_instance = None
_router_instance = None


def app(abstract: str | type | None = None) -> Any:
    """Resolve something from the application container."""
    if _app_instance is None:
        raise RuntimeError("Application not booted.")
    if abstract is None:
        return _app_instance
    return _app_instance.make(abstract)


def env(key: str, default: Any = None) -> Any:
    return os.environ.get(key, default)


def config(key: str, default: Any = None) -> Any:
    """Read a config value using dot notation: config('app.name')."""
    try:
        cfg = app("config")
        parts = key.split(".")
        val = cfg
        for part in parts:
            val = val[part]
        return val
    except Exception:
        return default


def route(name: str, **params) -> str:
    """Generate a URL for a named route."""
    if _router_instance is None:
        raise RuntimeError("Router not available.")
    return _router_instance.url_for(name, **params)


def redirect(url: str, status: int = 302):
    from caprail.http.response import Response
    return Response.redirect(url, status)


def view(template: str, data: dict | None = None):
    """Return a view response (must be awaited in async context)."""
    from caprail.view.engine import ViewEngine
    return ViewEngine.instance().render_response(template, data)


def abort(status: int, message: str = "") -> None:
    """Raise an HTTP exception."""
    from caprail.http.exceptions import HttpException
    raise HttpException(status, message)


def base_path(*parts: str) -> Path:
    if _app_instance is None:
        return Path.cwd().joinpath(*parts)
    return _app_instance.base_path.joinpath(*parts)


def storage_path(*parts: str) -> Path:
    if _app_instance is None:
        return Path.cwd() / "storage" / Path(*parts) if parts else Path.cwd() / "storage"
    return _app_instance.storage_path(*parts)


def public_path(*parts: str) -> Path:
    if _app_instance is None:
        return Path.cwd() / "public" / Path(*parts) if parts else Path.cwd() / "public"
    return _app_instance.public_path(*parts)
