# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import json
import logging
import os
import threading
import time
import unittest
import urllib.request
from unittest import TestCase

import docker

from liminal.build.python import PythonImageVersions
from liminal.build.service.python_server.python_server import PythonServerImageBuilder


class TestPythonServer(TestCase):

    def setUp(self) -> None:
        super().setUp()
        self.docker_client = docker.from_env()
        self.config = self.__create_conf('my_task')
        self.image_name = self.config['image']
        self.__remove_containers()

    def tearDown(self) -> None:
        self.__remove_containers()
        self.docker_client.close()

    def test_build_python_server(self):
        versions = [None] + list(PythonImageVersions().supported_versions)
        for version in versions:
            build_out = self.__test_build_python_server(python_version=version)
            self.assertTrue('RUN pip install -r requirements.txt' in build_out,
                            'Incorrect pip command')

    def test_build_python_server_with_pip_conf(self):
        build_out = self.__test_build_python_server(use_pip_conf=True)

        self.assertTrue(
            'RUN --mount=type=secret,id=pip_config,dst=/etc/pip.conf  pip install' in build_out,
            'Incorrect pip command')

    def __test_build_python_server(self, use_pip_conf=False,
                                   python_version=None):
        base_path = os.path.join(os.path.dirname(__file__), '../../../liminal')

        config = self.__create_conf('my_task')

        if use_pip_conf:
            config['pip_conf'] = os.path.join(base_path, 'pip.conf')

        if python_version:
            config['python_version'] = python_version

        builder = PythonServerImageBuilder(config=config,
                                           base_path=base_path,
                                           relative_source_path='myserver',
                                           tag=self.image_name)

        build_out = str(builder.build())

        thread = threading.Thread(target=self.__run_container, args=[self.image_name])
        thread.daemon = True
        thread.start()

        time.sleep(5)

        logging.info('Sending request to server')

        json_string = '{"key1": "val1", "key2": "val2"}'

        encoding = 'ascii'

        server_response = str(urllib.request.urlopen(
            'http://localhost:9294/myendpoint1',
            data=json_string.encode(encoding)
        ).read().decode(encoding))

        logging.info(f'Response from server: {server_response}')

        self.assertEqual(f'Input was: {json.loads(json_string)}', server_response)

        return build_out

    def __remove_containers(self):
        logging.info(f'Stopping containers with image: {self.image_name}')

        all_containers = self.docker_client.containers
        matching_containers = all_containers.list(filters={'ancestor': self.image_name})

        for container in matching_containers:
            container_id = container.id
            logging.info(f'Stopping container {container_id}')
            self.docker_client.api.stop(container_id)
            logging.info(f'Removing container {container_id}')
            self.docker_client.api.remove_container(container_id)

        self.docker_client.containers.prune()

    def __run_container(self, image_name):
        try:
            logging.info(f'Running container for image: {image_name}')
            self.docker_client.containers.run(image_name, ports={'80/tcp': 9294})
        except Exception as err:
            logging.exception(err)
            pass

    @staticmethod
    def __create_conf(task_id):
        return {
            'task': task_id,
            'cmd': 'foo bar',
            'image': 'liminal_server_image',
            'source': 'baz',
            'input_type': 'my_input_type',
            'input_path': 'my_input',
            'output_path': '/my_output.json',
            'no_cache': True,
            'endpoints': [
                {
                    'endpoint': '/myendpoint1',
                    'module': 'my_server',
                    'function': 'myendpoint1func'
                }
            ]
        }


if __name__ == '__main__':
    unittest.main()
