
import requests
import urllib.request
from unittest import TestCase
import datadiligence as dd
from datadiligence.rules import XRobotsTagHeader
import time

# starting local server to echo back headers
from werkzeug.serving import make_server
from server.app import app
import threading


class XRobotsTest(TestCase):
    @classmethod
    def setUpClass(cls):
        cls.server = make_server('localhost', 5001, app)
        cls.server_thread = threading.Thread(target=cls.server.serve_forever)
        cls.server_thread.start()
        time.sleep(1)  # wait for server to start

        cls.rule = XRobotsTagHeader(user_agent="spawningbot")
        cls.rule_2 = XRobotsTagHeader(user_agent=None)

    def test_noheader(self):
        self.assertTrue(self.rule._eval_header_value(""))
        self.assertTrue(self.rule._eval_header_value(None))
        self.assertTrue(self.rule_2._eval_header_value(""))
        self.assertTrue(self.rule_2._eval_header_value(None))

    def test_noai(self):
        self.assertFalse(self.rule._eval_header_value("noai"))
        self.assertFalse(self.rule._eval_header_value("noimageai"))
        self.assertFalse(self.rule._eval_header_value("other, noai"))
        self.assertFalse(self.rule_2._eval_header_value("noai"))
        self.assertFalse(self.rule_2._eval_header_value("noimageai"))
        self.assertFalse(self.rule_2._eval_header_value("other, noai"))

    def test_ai(self):
        self.assertTrue(self.rule._eval_header_value("other"))
        self.assertTrue(self.rule._eval_header_value("noindex"))
        self.assertTrue(self.rule._eval_header_value("other, noindex"))
        self.assertTrue(self.rule_2._eval_header_value("other"))
        self.assertTrue(self.rule_2._eval_header_value("noindex"))
        self.assertTrue(self.rule_2._eval_header_value("other, noindex"))

    def test_useragent_noai(self):
        self.assertFalse(self.rule._eval_header_value("spawningbot: noai"))
        self.assertFalse(self.rule._eval_header_value("spawningbot: noimageai"))
        self.assertFalse(self.rule._eval_header_value("other, spawningbot: noai"))
        self.assertFalse(self.rule._eval_header_value("other, spawningbot:noai"))
        self.assertFalse(self.rule._eval_header_value("spawningbot:other, spawningbot: noai"))
        self.assertFalse(self.rule._eval_header_value("spawningbot:other, spawningbot:noai"))
        self.assertTrue(self.rule_2._eval_header_value("spawningbot: noai"))
        self.assertTrue(self.rule_2._eval_header_value("spawningbot: noimageai"))
        self.assertTrue(self.rule_2._eval_header_value("other, spawningbot: noai"))
        self.assertTrue(self.rule_2._eval_header_value("other, spawningbot:noai"))
        self.assertTrue(self.rule_2._eval_header_value("spawningbot:other, spawningbot: noai"))
        self.assertTrue(self.rule_2._eval_header_value("spawningbot:other, spawningbot:noai"))

    def test_useragent_ai(self):
        self.assertTrue(self.rule._eval_header_value("spawningbot: all"))
        self.assertTrue(self.rule._eval_header_value("spawningbot: other"))
        self.assertTrue(self.rule._eval_header_value("other, spawningbot: all"))
        self.assertTrue(self.rule._eval_header_value("spawningbot: other, spawningbot: all, test:noai"))
        self.assertTrue(self.rule_2._eval_header_value("spawningbot: all"))
        self.assertTrue(self.rule_2._eval_header_value("spawningbot: other"))
        self.assertTrue(self.rule_2._eval_header_value("other, spawningbot: all"))
        self.assertTrue(self.rule_2._eval_header_value("spawningbot: other, spawningbot: all, test:noai"))

    def test_useragent_override(self):
        pass

    def test_stdlib(self):
        request = urllib.request.Request("http://localhost:5001/noai", data=None)
        with urllib.request.urlopen(request, timeout=3) as response:
            self.assertEqual(self.rule._handle_response(response), "noai")
            self.assertEqual(self.rule._handle_headers(response.headers), "noai")
            self.assertEqual(self.rule._handle_headers(response.getheaders()), "noai")
            self.assertFalse(self.rule.is_allowed(response=response))
            self.assertFalse(self.rule.is_allowed(headers=response.headers))

        request = urllib.request.Request("http://localhost:5001/ai", data=None)
        with urllib.request.urlopen(request, timeout=3) as response:
            self.assertEqual(self.rule._handle_response(response), "all")
            self.assertEqual(self.rule._handle_headers(response.headers), "all")
            self.assertTrue(self.rule.is_allowed(response=response))
            self.assertTrue(self.rule.is_allowed(headers=response.headers))

    def test_requests_lib(self):
        response = requests.get("http://localhost:5001/noai", timeout=3)
        self.assertEqual(self.rule._handle_response(response), "noai")
        self.assertEqual(self.rule._handle_headers(response.headers), "noai")
        self.assertFalse(self.rule.is_allowed(response=response))
        self.assertFalse(self.rule.is_allowed(headers=response.headers))

        response = requests.get("http://localhost:5001/ai")
        self.assertEqual(self.rule._handle_response(response), "all")
        self.assertEqual(self.rule._handle_headers(response.headers), "all")
        self.assertTrue(self.rule.is_allowed(response=response))
        self.assertTrue(self.rule.is_allowed(headers=response.headers))

    def test_useragent_requests(self):
        response = requests.get("http://localhost:5001/user_agents")
        self.assertTrue(self.rule.is_allowed(response=response))
        self.assertTrue(self.rule.is_allowed(headers=response.headers))

        response = requests.get("http://localhost:5001/user_agents_noai")
        self.assertFalse(self.rule.is_allowed(response=response))
        self.assertFalse(self.rule.is_allowed(headers=response.headers))

    def test_parse_useragents(self):
        response = requests.get("http://localhost:5001/user_agents")
        self.assertEqual(self.rule._handle_response(response), "demobot: noai, examplebot: noai, spawningbot: all")

    def test_malformed_headers(self):
        self.assertTrue(self.rule._eval_header_value(":,"))
        self.assertTrue(self.rule._eval_header_value(":, :, ,;: -:: "))

    def test_exceptions(self):
        self.assertRaises(dd.exceptions.XRobotsTagNoParam, self.rule.is_allowed, None, None)
        self.assertRaises(dd.exceptions.XRobotsTagUnknownHeaderObject, self.rule._handle_headers, None)
        self.assertRaises(dd.exceptions.XRobotsTagUnknownResponseObject, self.rule._handle_response, None)

    def test_url_arg(self):
        self.assertTrue(self.rule.is_allowed(url="http://localhost:5001/ai"))
        self.assertFalse(self.rule.is_allowed(url="http://localhost:5001/noai"))

    def test_noindex(self):
        rule = XRobotsTagHeader(user_agent="spawningbot", respect_noindex=False)
        self.assertTrue(rule.is_allowed(url="http://localhost:5001/noindex"))
        rule_2 = XRobotsTagHeader(user_agent="spawningbot", respect_noindex=True)
        self.assertFalse(rule_2.is_allowed(url="http://localhost:5001/noindex"))

    @classmethod
    def tearDownClass(cls):
        cls.server.shutdown()
        cls.server_thread.join()
