# -*- encoding: utf-8 -*-

import json
import tempfile
import unittest

from werkzeug.test import Client
from werkzeug.wrappers import Response

from isso import Isso, config, core
from isso.utils import http

from fixtures import curl, FakeIP

http.curl = curl


class TestGuard(unittest.TestCase):
    data = json.dumps({"text": "Lorem ipsum."})

    def setUp(self):
        self.path = tempfile.NamedTemporaryFile().name

    def makeClient(self, ip, ratelimit=2, direct_reply=3, self_reply=False, require_email=False, require_author=False):
        conf = config.load(config.default_file())
        conf.set("general", "dbpath", self.path)
        conf.set("hash", "algorithm", "none")
        conf.set("guard", "enabled", "true")
        conf.set("guard", "ratelimit", str(ratelimit))
        conf.set("guard", "direct-reply", str(direct_reply))
        conf.set("guard", "reply-to-self", "1" if self_reply else "0")
        conf.set("guard", "require-email", "1" if require_email else "0")
        conf.set("guard", "require-author", "1" if require_author else "0")

        class App(Isso, core.Mixin):
            pass

        app = App(conf)

        app.wsgi_app = FakeIP(app.wsgi_app, ip)

        return Client(app, Response)

    def testRateLimit(self):
        bob = self.makeClient("127.0.0.1", 2)

        for i in range(2):
            rv = bob.post("/new?uri=test", data=self.data)
            self.assertEqual(rv.status_code, 201)

        rv = bob.post("/new?uri=test", data=self.data)

        self.assertEqual(rv.status_code, 403)
        self.assertIn("ratelimit exceeded", rv.get_data(as_text=True))

        alice = self.makeClient("1.2.3.4", 2)
        for i in range(2):
            self.assertEqual(alice.post("/new?uri=test", data=self.data).status_code, 201)

        bob.application.db.execute(["UPDATE comments SET", "    created = created - 60", "WHERE remote_addr = '127.0.0.0'"])

        self.assertEqual(bob.post("/new?uri=test", data=self.data).status_code, 201)

    def testDirectReply(self):
        client = self.makeClient("127.0.0.1", 15, 3)

        for url in ("foo", "bar", "baz", "spam"):
            for _ in range(3):
                rv = client.post("/new?uri=%s" % url, data=self.data)
                self.assertEqual(rv.status_code, 201)

        for url in ("foo", "bar", "baz", "spam"):
            rv = client.post("/new?uri=%s" % url, data=self.data)

            self.assertEqual(rv.status_code, 403)
            self.assertIn("direct responses to", rv.get_data(as_text=True))

    def testSelfReply(self):
        def payload(id):
            return json.dumps({"text": "...", "parent": id})

        client = self.makeClient("127.0.0.1", self_reply=False)
        self.assertEqual(client.post("/new?uri=test", data=self.data).status_code, 201)
        self.assertEqual(client.post("/new?uri=test", data=payload(1)).status_code, 403)

        client.application.db.execute(
            ["UPDATE comments SET", "    created = created - ?", "WHERE id = 1"],
            (client.application.conf.getint("general", "max-age"),),
        )

        self.assertEqual(client.post("/new?uri=test", data=payload(1)).status_code, 201)

        client = self.makeClient("128.0.0.1", ratelimit=3, self_reply=False)
        self.assertEqual(client.post("/new?uri=test", data=self.data).status_code, 201)
        self.assertEqual(client.post("/new?uri=test", data=payload(1)).status_code, 201)
        self.assertEqual(client.post("/new?uri=test", data=payload(2)).status_code, 201)

    def testRequireEmail(self):
        def payload(email):
            return json.dumps({"text": "...", "email": email})

        client = self.makeClient("127.0.0.1", ratelimit=4, require_email=False)
        client_strict = self.makeClient("127.0.0.2", ratelimit=4, require_email=True)

        # if we don't require email
        self.assertEqual(client.post("/new?uri=test", data=payload("")).status_code, 201)
        self.assertEqual(client.post("/new?uri=test", data=payload("test@me.more")).status_code, 201)

        # if we do require email
        self.assertEqual(client_strict.post("/new?uri=test", data=payload("")).status_code, 403)
        self.assertEqual(client_strict.post("/new?uri=test", data=payload("test@me.more")).status_code, 201)

    def testRequireAuthor(self):
        def payload(author):
            return json.dumps({"text": "...", "author": author})

        client = self.makeClient("127.0.0.1", ratelimit=4, require_author=False)
        client_strict = self.makeClient("127.0.0.2", ratelimit=4, require_author=True)

        # if we don't require author
        self.assertEqual(client.post("/new?uri=test", data=payload("")).status_code, 201)
        self.assertEqual(client.post("/new?uri=test", data=payload("pipo author")).status_code, 201)

        # if we do require author
        self.assertEqual(client_strict.post("/new?uri=test", data=payload("")).status_code, 403)
        self.assertEqual(client_strict.post("/new?uri=test", data=payload("pipo author")).status_code, 201)
