import os
import podonos
import unittest
from unittest import mock
from requests import Response
import json as pyjson

from podonos.core.file import File
from podonos.common.constant import *


# Mocks HTTP GET request.
def _make_response(text=None, json_data=None, status_code=200) -> Response:
    resp = Response()
    resp.status_code = status_code
    if json_data is not None:
        resp._content = pyjson.dumps(json_data).encode("utf-8")
        resp.headers["Content-Type"] = "application/json"
    elif text is not None:
        resp._content = str(text).encode("utf-8")
    else:
        resp._content = b""
    return resp


def mocked_requests_get(*args, **kwargs):
    if "/customers/verify/api-key" in args[0]:
        # API key verification
        return _make_response(text="true", status_code=200)

    if "/version/sdk" in args[0]:
        # SDK versions
        version_response = dict(latest="0.1.5", recommended="0.1.4", minimum="0.1.0")
        return _make_response(json_data=version_response, status_code=200)

    if "/customers/uploading-presigned-url" in args[0]:
        return _make_response(text="https://fake.podonos.com/my_url1", status_code=200)

    return _make_response(status_code=404)


def mocked_requests_post(*args, **kwargs):
    if "/evaluations" in args[0]:
        # evaluations
        evaluation_response = dict(
            id="mock_id",
            title="mock_title",
            internal_name="mock_internal_name",
            description="mock_desc",
            batch_size=1,
            status="mock_status",
            created_time="2024-05-21T06:18:09.659270Z",
            updated_time="2024-05-22T06:18:09.659270Z",
        )
        return _make_response(json_data=evaluation_response, status_code=200)

    return _make_response(status_code=404)


class TestPodonos(unittest.TestCase):

    @mock.patch("requests.get", side_effect=mocked_requests_get)
    def test_init(self, mock_get):
        # Invalid api_key
        invalid_api_key = "1"
        with self.assertRaises(Exception) as context:
            _ = podonos.init(invalid_api_key)

        # Valid api_key
        valid_api_key = "12345678"
        valid_client = podonos.init(valid_api_key)
        self.assertTrue(isinstance(valid_client, podonos.Client))

    @mock.patch("requests.get", side_effect=mocked_requests_get)
    def test_init_api_key_env(self, mock_get):
        # Valid api_key_env
        os.environ[PODONOS_API_KEY] = "ABCDEFG"
        valid_client = podonos.init()
        self.assertTrue(isinstance(valid_client, podonos.Client))

    @mock.patch("requests.get", side_effect=mocked_requests_get)
    def test_init_both_api_keys(self, mock_get):
        # Valid api_key_env
        os.environ[PODONOS_API_KEY] = "ABCDEFG"
        valid_api_key = "12345678"
        valid_client = podonos.init(valid_api_key)
        self.assertTrue(isinstance(valid_client, podonos.Client))


class TestPodonosClient(unittest.TestCase):

    @mock.patch("requests.get", side_effect=mocked_requests_get)
    def setUp(self, mock_get) -> None:
        valid_api_key = "1234567890"
        self._mock_client = podonos.init(api_key=valid_api_key)

        self.config = {"name": "my_new_model_03272024_p1_k2_en_us", "desc": "Updated model", "type": "NMOS", "lan": "en-us"}

    @mock.patch("requests.get", side_effect=mocked_requests_get)
    @mock.patch("requests.post", side_effect=mocked_requests_post)
    def test_create_evaluator(self, mock_get, mock_post):
        # Missing name is allowed.
        etor = self._mock_client.create_evaluator(desc=self.config["desc"], type=self.config["type"], lan=self.config["lan"])
        self.assertIsNotNone(etor)

        # Too short name.
        with self.assertRaises(ValueError) as context:
            _ = self._mock_client.create_evaluator(name="a", desc=self.config["desc"], type=self.config["type"], lan=self.config["lan"])

        # Missing description is allowed.
        etor = self._mock_client.create_evaluator(name=self.config["name"], type=self.config["type"], lan=self.config["lan"])
        self.assertIsNotNone(etor)

        # Unknown type.
        with self.assertRaises(ValueError) as context:
            _ = self._mock_client.create_evaluator(name=self.config["name"], desc=self.config["desc"], type="unknown_type", lan=self.config["lan"])

        # Missing language is allowed.
        etor = self._mock_client.create_evaluator(name=self.config["name"], desc=self.config["desc"], type=self.config["type"])
        self.assertIsNotNone(etor)

        # Invalid language.
        with self.assertRaises(ValueError) as context:
            _ = self._mock_client.create_evaluator(name=self.config["name"], desc=self.config["desc"], type=self.config["type"], lan="abcd")

        # Valid configuration
        etor = self._mock_client.create_evaluator(
            name=self.config["name"], desc=self.config["desc"], type=self.config["type"], lan=self.config["lan"]
        )
        self.assertIsNotNone(etor)

        # P.808
        etor = self._mock_client.create_evaluator(name=self.config["name"], desc=self.config["desc"], type="P808", lan=self.config["lan"])
        self.assertIsNotNone(etor)

        # SMOS
        etor = self._mock_client.create_evaluator(name=self.config["name"], desc=self.config["desc"], type="SMOS", lan=self.config["lan"])
        self.assertIsNotNone(etor)

    @mock.patch("requests.get", side_effect=mocked_requests_get)
    @mock.patch("requests.post", side_effect=mocked_requests_post)
    def test_create_evaluator_with_en_in_language(self, mock_get, mock_post):
        """Test creating evaluator with en-in language"""
        # Test with en-in language
        etor = self._mock_client.create_evaluator(name="test_en_in_evaluator", desc="Test evaluator for Indian English", type="NMOS", lan="en-in")
        self.assertIsNotNone(etor)

        # Test with different evaluation types using en-in
        for eval_type in ["NMOS", "QMOS", "SMOS", "P808", "PREF", "CSMOS"]:
            etor = self._mock_client.create_evaluator(
                name=f"test_en_in_{eval_type.lower()}", desc=f"Test {eval_type} evaluator for Indian English", type=eval_type, lan="en-in"
            )
            self.assertIsNotNone(etor)


class TestPodonosEvaluator(unittest.TestCase):

    @unittest.skip("skipped")
    @mock.patch("requests.get", side_effect=mocked_requests_get)
    def test_evaluator(self, mock_get):
        valid_api_key = "1234567890"
        self._mock_client = podonos.init(api_key=valid_api_key)

        self.config = {"name": "my_new_model_03272024_p1_k2_en_us", "desc": "Updated model", "type": "NMOS", "lan": "en-us"}

        etor = self._mock_client.create_evaluator(name="new_model", desc="", type="NMOS", lan="en-au")
        self.assertIsNotNone(etor)

        some_file = os.path.join(os.path.dirname(__file__), "../speech_0_0.mp3")
        etor.add_file(File(path=some_file, model_tag="my_new_model", tags=["unknown_file,new_model"]))
        etor.close()


if __name__ == "__main__":
    unittest.main(verbosity=2)
