"""
SAYTHON Framework - Request Object
"""
import json
import urllib.parse
from typing import Any, Optional


class Request:
    """
    Wraps a WSGI environ dict into a friendly object.

    Usage:
        req.method         -> 'GET', 'POST', ...
        req.path           -> '/users/1'
        req.json           -> parsed JSON body dict
        req.query          -> {'page': '1', 'limit': '10'}
        req.params         -> URL path params {'id': '1'}
        req.headers        -> dict of HTTP headers
        req.body           -> raw bytes
        req.user           -> set by auth middleware
    """

    def __init__(self, environ: dict):
        self._environ = environ
        self.method: str = environ.get("REQUEST_METHOD", "GET").upper()
        self.path: str = environ.get("PATH_INFO", "/")
        self.params: dict = {}          # filled by router (path params)
        self.user: Optional[Any] = None  # filled by @auth_required
        self._json_cache = None
        self._body_cache = None

    # ------------------------------------------------------------------ #
    #  Query string  →  /items?page=2&limit=5
    # ------------------------------------------------------------------ #
    @property
    def query(self) -> dict:
        qs = self._environ.get("QUERY_STRING", "")
        return dict(urllib.parse.parse_qsl(qs))

    # ------------------------------------------------------------------ #
    #  Raw body bytes
    # ------------------------------------------------------------------ #
    @property
    def body(self) -> bytes:
        if self._body_cache is None:
            try:
                length = int(self._environ.get("CONTENT_LENGTH") or 0)
            except ValueError:
                length = 0
            self._body_cache = self._environ["wsgi.input"].read(length) if length else b""
        return self._body_cache

    # ------------------------------------------------------------------ #
    #  Parsed JSON body
    # ------------------------------------------------------------------ #
    @property
    def json(self) -> dict:
        if self._json_cache is None:
            try:
                self._json_cache = json.loads(self.body.decode("utf-8")) if self.body else {}
            except (json.JSONDecodeError, UnicodeDecodeError):
                self._json_cache = {}
        return self._json_cache

    # ------------------------------------------------------------------ #
    #  HTTP Headers
    # ------------------------------------------------------------------ #
    @property
    def headers(self) -> dict:
        headers = {}
        for key, value in self._environ.items():
            if key.startswith("HTTP_"):
                name = key[5:].replace("_", "-").title()
                headers[name] = value
        if "CONTENT_TYPE" in self._environ:
            headers["Content-Type"] = self._environ["CONTENT_TYPE"]
        if "CONTENT_LENGTH" in self._environ:
            headers["Content-Length"] = self._environ["CONTENT_LENGTH"]
        return headers

    def get_header(self, name: str, default=None) -> Optional[str]:
        """Get a single header by name (case-insensitive)."""
        key = "HTTP_" + name.upper().replace("-", "_")
        return self._environ.get(key, default)

    # ------------------------------------------------------------------ #
    #  Authorization header helper
    # ------------------------------------------------------------------ #
    @property
    def auth_token(self) -> Optional[str]:
        """Extract Bearer token from Authorization header."""
        auth = self.get_header("Authorization", "")
        if auth and auth.startswith("Bearer "):
            return auth[7:]
        return None

    def __repr__(self):
        return f"<Request {self.method} {self.path}>"
