import requests
from urllib.parse import urlencode, quote


class CFSpiderResponse:
    def __init__(self, response, cf_colo=None, cf_ray=None):
        self._response = response
        self.cf_colo = cf_colo
        self.cf_ray = cf_ray
    
    @property
    def text(self):
        return self._response.text
    
    @property
    def content(self):
        return self._response.content
    
    @property
    def status_code(self):
        return self._response.status_code
    
    @property
    def headers(self):
        return self._response.headers
    
    @property
    def cookies(self):
        return self._response.cookies
    
    @property
    def url(self):
        return self._response.url
    
    @property
    def encoding(self):
        return self._response.encoding
    
    @encoding.setter
    def encoding(self, value):
        self._response.encoding = value
    
    def json(self, **kwargs):
        return self._response.json(**kwargs)
    
    def raise_for_status(self):
        self._response.raise_for_status()


def request(method, url, cf_proxies=None, **kwargs):
    if not cf_proxies:
        raise ValueError("cf_proxies is required")
    
    cf_proxies = cf_proxies.rstrip("/")
    
    params = kwargs.pop("params", None)
    headers = kwargs.pop("headers", {})
    data = kwargs.pop("data", None)
    json_data = kwargs.pop("json", None)
    cookies = kwargs.pop("cookies", None)
    timeout = kwargs.pop("timeout", 30)
    
    target_url = url
    if params:
        target_url = f"{url}?{urlencode(params)}"
    
    proxy_url = f"{cf_proxies}/proxy?url={quote(target_url, safe='')}&method={method.upper()}"
    
    request_headers = {}
    if headers:
        for key, value in headers.items():
            request_headers[f"X-CFSpider-Header-{key}"] = value
    
    if cookies:
        cookie_str = "; ".join([f"{k}={v}" for k, v in cookies.items()])
        request_headers["X-CFSpider-Header-Cookie"] = cookie_str
    
    response = requests.post(
        proxy_url,
        headers=request_headers,
        data=data,
        json=json_data,
        timeout=timeout,
        **kwargs
    )
    
    cf_colo = response.headers.get("X-CF-Colo")
    cf_ray = response.headers.get("CF-Ray")
    
    return CFSpiderResponse(response, cf_colo=cf_colo, cf_ray=cf_ray)


def get(url, cf_proxies=None, **kwargs):
    return request("GET", url, cf_proxies=cf_proxies, **kwargs)


def post(url, cf_proxies=None, **kwargs):
    return request("POST", url, cf_proxies=cf_proxies, **kwargs)


def put(url, cf_proxies=None, **kwargs):
    return request("PUT", url, cf_proxies=cf_proxies, **kwargs)


def delete(url, cf_proxies=None, **kwargs):
    return request("DELETE", url, cf_proxies=cf_proxies, **kwargs)


def head(url, cf_proxies=None, **kwargs):
    return request("HEAD", url, cf_proxies=cf_proxies, **kwargs)


def options(url, cf_proxies=None, **kwargs):
    return request("OPTIONS", url, cf_proxies=cf_proxies, **kwargs)


def patch(url, cf_proxies=None, **kwargs):
    return request("PATCH", url, cf_proxies=cf_proxies, **kwargs)

