# -*- coding: utf-8 -*-
# Copyright: 2016, Ableton AG, Berlin. All rights reserved.
import json
import unittest

import mock

from abl.vpath.base import URI
from abl.webconnector.fileprocessing import filter_info_files
from abl.webconnector.infoprocessing import (
    InfoFileProcessingError,
    combine_files,
    upload_info,
)

from .common import cleanup_memory_fs, create_file


class InfoProcessingTests(unittest.TestCase):
    def tearDown(self):
        cleanup_memory_fs()
        super(InfoProcessingTests, self).tearDown()

    def test_file_combination(self):
        a = {"key": "value"}
        b = ["a", "list", "with", "items"]
        combined = dict(a=a, b=b)
        base = URI("memory:///")
        af = base / "timestamp.a+info"
        bf = base / "timestamp.b+info"
        for f, content in ((af, a), (bf, b)):
            with f.open("w") as outf:
                outf.write(json.dumps(content))

        self.assertEqual(combined, json.loads(combine_files(af, bf)))

    def test_filtering_info_files(self):
        base = URI("memory:///timestamp.")
        all_files = [
            create_file(base + ext) for ext in ("live+info", "push+info", "log", "wc")
        ]
        self.assertEqual(
            [base + "live+info", base + "push+info"], list(filter_info_files(all_files))
        )

    @mock.patch("urllib2.urlopen")
    def test_uploading_info_files(self, urlopen_mock):
        response = mock.MagicMock()
        urlopen_mock.return_value = response
        response.getcode.return_value = 200

        url = "http://localhost:8080/"
        base = URI("memory:///")
        af = base / "timestamp.a+info"
        with af.open("w") as outf:
            outf.write(json.dumps({"key": "value"}))

        create_file(base / "timestamp.log")

        upload_info(url, base)

        self.assertEqual(1, len(urlopen_mock.call_args_list))
        (req,), _ = urlopen_mock.call_args_list[0]
        self.assertEqual("POST", req.get_method())
        self.assertEqual(url, req.get_full_url())
        self.assertEqual({"a": {"key": "value"}}, json.loads(req.get_data()))

    @mock.patch("urllib2.urlopen")
    def test_failing_uploading_info_files_raises_error(self, urlopen_mock):
        response = urlopen_mock()
        response.getcode.return_value = 500

        base = URI("memory:///")
        af = base / "timestamp.a+info"
        with af.open("w") as outf:
            outf.write(json.dumps({"key": "value"}))

        create_file(base / "timestamp.log")

        self.assertRaises(
            InfoFileProcessingError, upload_info, "http://localhost:8080/", base
        )

    @mock.patch("urllib2.urlopen")
    def test_uploading_info_files_ignores_files_without_pivot(self, urlopen_mock):
        url = "http://localhost:8080/"
        base = URI("memory:///")

        af = base / "timestamp.a+info"
        with af.open("w") as outf:
            outf.write(json.dumps({"key": "value"}))

        upload_info(url, base)

        self.assertEqual(0, len(urlopen_mock.call_args_list))

    @mock.patch("urllib2.urlopen")
    def test_uploading_info_files_removes_them(self, urlopen_mock):
        response = mock.MagicMock()
        urlopen_mock.return_value = response
        response.getcode.return_value = 200

        url = "http://localhost:8080/"
        base = URI("memory:///")
        af = base / "timestamp.a+info"
        with af.open("w") as outf:
            outf.write(json.dumps({"key": "value"}))

        create_file(base / "timestamp.log")

        upload_info(url, base)

        self.assertEqual(1, len(urlopen_mock.call_args_list))
        self.assertFalse(af.exists())

    @mock.patch("urllib2.urlopen")
    def test_no_enpoint_doesnt_upload_but_info_files_are_removed(self, urlopen_mock):
        url = None
        base = URI("memory:///")
        af = base / "timestamp.a+info"
        with af.open("w") as outf:
            outf.write(json.dumps({"key": "value"}))

        create_file(base / "timestamp.log")

        upload_info(url, base)

        self.assertFalse(urlopen_mock.call_args_list)
        self.assertFalse(af.exists())

    @mock.patch("urllib2.urlopen")
    def test_enpoint_crash_still_removes_info_files(self, urlopen_mock):
        urlopen_mock.side_effect = Exception

        url = "http://foobar/"
        base = URI("memory:///")
        af = base / "timestamp.a+info"
        with af.open("w") as outf:
            outf.write(json.dumps({"key": "value"}))

        create_file(base / "timestamp.log")

        self.assertRaises(Exception, upload_info, url, base)

        self.assertFalse(af.exists())
