# -*- coding: utf-8 -*-
import flask

from ddtrace import Pin
from ddtrace.ext import http
from ddtrace.vendor import wrapt
from tests.utils import TracerTestCase
from tests.utils import assert_is_measured
from tests.utils import assert_span_http_status_code


class FlaskAutopatchTestCase(TracerTestCase):
    def setUp(self):
        super(FlaskAutopatchTestCase, self).setUp()
        self.app = flask.Flask(__name__)
        Pin.override(self.app, service="test-flask", tracer=self.tracer)
        self.client = self.app.test_client()

    def test_patched(self):
        """
        When using ddtrace-run
            Then the `flask` module is patched
        """
        # DEV: We have great test coverage in tests.contrib.flask,
        #      we only need basic tests here to assert `ddtrace-run` patched thingsa

        # Assert module is marked as patched
        self.assertTrue(flask._datadog_patch)

        # Assert our instance of flask.app.Flask is patched
        self.assertTrue(isinstance(self.app.add_url_rule, wrapt.ObjectProxy))
        self.assertTrue(isinstance(self.app.wsgi_app, wrapt.ObjectProxy))

        # Assert the base module flask.app.Flask methods are patched
        self.assertTrue(isinstance(flask.app.Flask.add_url_rule, wrapt.ObjectProxy))
        self.assertTrue(isinstance(flask.app.Flask.wsgi_app, wrapt.ObjectProxy))

    def test_request(self):
        """
        When using ddtrace-run
            When making a request to flask app
                We generate the expected spans
        """

        @self.app.route("/")
        def index():
            return "Hello Flask", 200

        res = self.client.get("/")
        self.assertEqual(res.status_code, 200)
        self.assertEqual(res.data, b"Hello Flask")

        spans = self.pop_spans()
        self.assertEqual(len(spans), 8)

        self.assertListEqual(
            [
                "flask.request",
                "flask.try_trigger_before_first_request_functions",
                "flask.preprocess_request",
                "flask.dispatch_request",
                "tests.contrib.flask_autopatch.test_flask_autopatch.index",
                "flask.process_response",
                "flask.do_teardown_request",
                "flask.do_teardown_appcontext",
            ],
            [s.name for s in spans],
        )

        # Assert span services
        for span in spans:
            self.assertEqual(span.service, "test-flask")

        # Root request span
        req_span = spans[0]
        assert_is_measured(req_span)
        self.assertEqual(req_span.service, "test-flask")
        self.assertEqual(req_span.name, "flask.request")
        self.assertEqual(req_span.resource, "GET /")
        self.assertEqual(req_span.span_type, "web")
        self.assertEqual(req_span.error, 0)
        self.assertIsNone(req_span.parent_id)

        # Request tags
        for tag in ["flask.version", "http.url", "http.method", "http.status_code", "flask.endpoint", "flask.url_rule"]:
            assert tag in req_span.meta

        self.assertEqual(req_span.get_tag("flask.endpoint"), "index")
        self.assertEqual(req_span.get_tag("flask.url_rule"), "/")
        self.assertEqual(req_span.get_tag("http.method"), "GET")
        self.assertEqual(req_span.get_tag(http.URL), "http://localhost/")
        assert_span_http_status_code(req_span, 200)

        # Handler span
        handler_span = spans[4]
        self.assertEqual(handler_span.service, "test-flask")
        self.assertEqual(handler_span.name, "tests.contrib.flask_autopatch.test_flask_autopatch.index")
        self.assertEqual(handler_span.resource, "/")
        self.assertEqual(req_span.error, 0)
