###############################################################################
#
# (C) Copyright 2023 EVERYSK TECHNOLOGIES
#
# This is an unpublished work containing confidential and proprietary
# information of EVERYSK TECHNOLOGIES. Disclosure, use, or reproduction
# without authorization of EVERYSK TECHNOLOGIES is prohibited.
#
###############################################################################

###############################################################################
#   Imports
###############################################################################
from everysk.config import settings
from everysk.core.compress import compress
from everysk.core.datetime import DateTime
from everysk.core.exceptions import RequiredError, SDKValueError
from everysk.core.http import HttpSDKPOSTConnection
from everysk.core.object import CLASS_KEY
from everysk.core.unittests import TestCase, mock

from everysk.sdk.entities.file.base import File


###############################################################################
#   File TestCase Implementation
###############################################################################
class FileTestCase(TestCase):

    def setUp(self):
        self.sample_data = {
            'id': 'file_1234567891011211234567890',
            'name': 'SampleFile',
            'tags': ['tag1', 'tag2'],
            'description': 'Description',
            'link_uid': 'link_uid',
            'workspace': 'main',
            'date': DateTime(2023, 9, 9, 9, 9, 9, 9),
            'data': 'base64data',
            'url': '/1234567891011211234567890',
            'content_type': 'text/csv',
            'version': '1.0',
            'created_on': DateTime(2023, 9, 9, 9, 9, 9, 9),
            'updated_on': DateTime(2023, 9, 9, 9, 9, 9, 9),
            'hash': '4a0ed08522000734bb845f5d72673d9d113c8236',
        }
        self.file = File(**self.sample_data)
        self.headers = HttpSDKPOSTConnection().get_headers()
        self.api_url = HttpSDKPOSTConnection().get_url()

    def test_get_id_prefix(self):
        self.assertEqual(File.get_id_prefix(), settings.FILE_ID_PREFIX)

    def test_validate(self):
        expected_data = compress({'class_name': 'File', 'method_name': 'validate', 'self_obj': self.file.to_dict(add_class_path=True), 'params': {}}, protocol='gzip', serialize='json')
        file: File = self.file.copy()

        with mock.patch('requests.post') as mock_post:
            mock_post.return_value.content = '{}'
            mock_post.return_value.status_code = 200
            file.validate()

        mock_post.assert_called_with(
            url=self.api_url,
            headers=self.headers,
            verify=settings.HTTP_DEFAULT_SSL_VERIFY,
            timeout=settings.EVERYSK_SDK_HTTP_DEFAULT_TIMEOUT,
            data=expected_data
        )

    def test_validate_transient(self):
        expected_data = compress({'class_name': 'File', 'method_name': 'validate_transient', 'self_obj': None, 'params': {'entity_dict': self.file.to_dict(add_class_path=True)}}, protocol='gzip', serialize='json')
        file: File = self.file.copy()

        with mock.patch('requests.post') as mock_post:
            mock_post.return_value.content = '{}'
            mock_post.return_value.status_code = 200
            File.validate_transient(file)

        mock_post.assert_called_with(
            url=self.api_url,
            headers=self.headers,
            verify=settings.HTTP_DEFAULT_SSL_VERIFY,
            timeout=settings.EVERYSK_SDK_HTTP_DEFAULT_TIMEOUT,
            data=expected_data
        )

    def test_entity_to_query(self):
        file: File = self.file.copy()
        self.assertRaisesRegex(
            SDKValueError,
            "Can't filter by Name and Tags at the same time",
            file.to_query
        )

        # Test with name
        file.pop('tags')
        file.pop('link_uid')
        file.pop('url')
        query = file.to_query() #pylint: disable=protected-access
        self.assertListEqual(query.filters, [
            ('workspace', '=', 'main'),
            ('name', '<', 'samplefilf'),
            ('name', '>=', 'samplefile'),
            ('date', '=', self.sample_data['date'])
        ])
        self.assertEqual(query.order, [])
        self.assertEqual(query.projection, None)
        self.assertEqual(query.limit, None)
        self.assertEqual(query.offset, None)
        self.assertEqual(query.page_size, None)
        self.assertEqual(query.page_token, None)
        self.assertEqual(query.distinct_on, [])

        # Test with tags
        file.update({'name': None, 'tags': ['tag1', 'tag2']})
        query = file.to_query() #pylint: disable=protected-access
        self.assertListEqual(query.filters, [
            ('workspace', '=', 'main'),
            ('date', '=', self.sample_data['date']),
            ('tags', '=', 'tag1'),
            ('tags', '=', 'tag2')
        ])

        # Test with link_uid
        file.update({'tags': None, 'link_uid': 'link_uid'})
        query = file.to_query() #pylint: disable=protected-access
        self.assertListEqual(query.filters, [
            ('workspace', '=', 'main'),
            ('link_uid', '=', 'link_uid'),
            ('date', '=', self.sample_data['date'])
        ])

        # Test with url
        file.update({'link_uid': None, 'url': '/1234567891011211234567890'})
        query = file.to_query() #pylint: disable=protected-access
        self.assertListEqual(query.filters, [
            ('workspace', '=', 'main'),
            ('date', '=', self.sample_data['date']),
            ('url', '=', '/1234567891011211234567890')
        ])

    def test_generate_url(self):
        file: File = self.file.copy()
        url = file.generate_url()
        with mock.patch('everysk.sdk.entities.file.base.generate_unique_id') as mock_generate_unique_id:
            mock_generate_unique_id.return_value = '1234567891011211234567890'
            url = file.generate_url()
        self.assertEqual(url, '/1234567891011211234567890')

    def test_required_fields(self):
        file: File = self.file.copy()
        file.id = None
        self.assertRaisesRegex(
            RequiredError,
            'The id attribute is required.',
            file.validate_required_fields
        )

        file.id = 'file_1234567891011211234567890'
        file.name = None
        self.assertRaisesRegex(
            RequiredError,
            'The name attribute is required.',
            file.validate_required_fields
        )

        file.name = 'SampleFile'
        file.workspace = None
        self.assertRaisesRegex(
            RequiredError,
            'The workspace attribute is required.',
            file.validate_required_fields
        )

        file.workspace = 'main'
        file.date = None
        self.assertRaisesRegex(
            RequiredError,
            'The date attribute is required.',
            file.validate_required_fields
        )

        file.date = DateTime(2023, 9, 9, 9, 9, 9, 9)
        file.hash = None
        self.assertRaisesRegex(
            RequiredError,
            'The hash attribute is required.',
            file.validate_required_fields
        )

        file.hash = '4a0ed08522000734bb845f5d72673d9d113c8236'
        file.data = None
        self.assertRaisesRegex(
            RequiredError,
            'The data attribute is required.',
            file.validate_required_fields
        )

        file.data = 'base64data'
        file.content_type = None
        self.assertRaisesRegex(
            RequiredError,
            'The content_type attribute is required.',
            file.validate_required_fields
        )

        file.content_type = 'text/csv'
        file.url = None
        self.assertRaisesRegex(
            RequiredError,
            'The url attribute is required.',
            file.validate_required_fields
        )

    def test_check_query_raises_sdk_error(self):
        with self.assertRaises(SDKValueError) as context:
            file: File = self.file.copy()
            file['tags'] = []
            file['link_uid'] = ''
            file.to_query(limit=1)

        self.assertEqual(str(context.exception), "Can't filter by URL and Name, Tags or Link UID at the same time")

    def test_to_dict_file(self):
        result = self.file.to_dict()
        expected_data = {
            'id': 'file_1234567891011211234567890',
            'name': 'SampleFile',
            'tags': ['tag1',
            'tag2'],
            'description': 'Description',
            'link_uid': 'link_uid',
            'workspace': 'main',
            'date': '20230909',
            'data': 'base64data',
            'url': '/file/1234567891011211234567890',
            'content_type': 'text/csv',
            'version': '1.0',
            'hash': '4a0ed08522000734bb845f5d72673d9d113c8236',
            'date_time': '20230909 09:09:09',
            'created': 1694250549,
            'updated': 1694250549
        }

        self.assertIsInstance(result, dict)
        self.assertEqual(result, expected_data)
