import contextlib
import os
from pathlib import Path
from tempfile import NamedTemporaryFile

import pytest
from django.http import FileResponse, HttpResponse

from ninja import NinjaAPI
from ninja.main import ConfigError
from ninja.testing import TestClient

api = NinjaAPI()

client = TestClient(api)

# TODO: check if you add  operation to the same path - it should raise a ConfigError that this path already exist
# make sure to check how this will work with versioning
# and also check what will happen if you add same path in different routers
#  api.add_router("", router1)
#  api.add_router("", router2)
# and both routers have same path defined


@api.get("")
def emptypath(request):
    return "/"


@api.get("/get")
def get(request):
    return f"this is {request.method}"


@api.post("/post")
def post(request):
    return f"this is {request.method}"


@api.put("/put")
def put(request):
    return f"this is {request.method}"


@api.patch("/patch")
def patch(request):
    return f"this is {request.method}"


@api.delete("/delete")
def delete(request):
    return f"this is {request.method}"


@api.api_operation(["GET", "POST"], "/multi")
def multiple(request):
    return f"this is {request.method}"


@api.get("/html")
def html(request):
    return HttpResponse("html")


@api.get("/file")
def file_response(request):
    tmp = NamedTemporaryFile(delete=False)
    try:
        p = Path(tmp.name)
        p.write_bytes(b"this is a file")
        return FileResponse(Path(tmp.name).open("rb"))
    finally:
        with contextlib.suppress(PermissionError):
            Path(tmp.name).unlink()


@pytest.mark.parametrize(
    "method,path,expected_status,expected_data,expected_streaming",
    [
        ("get", "/", 200, "/", False),
        ("get", "/get", 200, "this is GET", False),
        ("post", "/post", 200, "this is POST", False),
        ("put", "/put", 200, "this is PUT", False),
        ("patch", "/patch", 200, "this is PATCH", False),
        ("delete", "/delete", 200, "this is DELETE", False),
        ("get", "/multi", 200, "this is GET", False),
        ("post", "/multi", 200, "this is POST", False),
        ("patch", "/multi", 405, b"Method not allowed", False),
        ("get", "/html", 200, b"html", False),
        ("get", "/file", 200, b"this is a file", True),
    ],
)
def test_method(method, path, expected_status, expected_data, expected_streaming):
    func = getattr(client, method)
    response = func(path)
    assert response.status_code == expected_status
    assert response.streaming == expected_streaming
    try:
        data = response.json()
    except Exception:
        data = response.content
    assert data == expected_data


def test_validates():
    try:
        os.environ["NINJA_SKIP_REGISTRY"] = ""
        with pytest.raises(ConfigError):
            _urls = NinjaAPI().urls
    finally:
        os.environ["NINJA_SKIP_REGISTRY"] = "yes"
