from collections import OrderedDict
from unittest.mock import patch

import pytest
from src.config.objects import TargetObject
from src.convert_crm_csv_data_process import convert_crm_csv_data_process
from src.error.exceptions import DataConvertException
from src.system_var.constants import CONV_JP_NAME
from src.util.execute_datetime import ExecuteDateTime

from .test_utils.log_message import generate_log_message_tuple


class TestConvertCrmCsvDataProcess:

    def test_run_process_success(self, caplog):
        """
        Cases:
            CSV変換処理が正常終了し、期待通りの結果が返ること
        Arranges:
            - チェック対象のdictオブジェクトを宣言する
        Expects:
            - CSV変換処理の結果文字列が返却されること
            - CSV変換処理の仕様に沿った正常系ログが出力されること(デバッグログは除く)
        """
        # Arrange
        response_json = [
            OrderedDict([
                ('attributes', OrderedDict([('type', 'Account'),
                 ('url', '/services/data/v1.0/sobjects/Account/TEST001')])),
                ('Id', 'TEST001'),
                ('AccountNumber', 'test001'),
                ('LastModifiedDate', '2022-06-01T00:00:00.000+0000'),
                ('LastModifiedById', 1.234567E+6),
                ('SystemModstamp', '2022-06-01T00:00:00.000+0000'),
                ('IsDeleted', True),
                ('PersonMailingAddress', OrderedDict([
                    ('PersonMailingStreet', 'Lorem ipsum dolor sit amet, \nconsectetur adipiscing elit, \nsed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'),  # noqa: E501
                    ('PersonMailingCity', 'New york city'),
                    ('PersonMailingState', 'Ohaio'),
                    ('PersonMailingPostalCode', '999-9999'),
                    ('PersonMailingCountry', 'US'),
                    ('PersonMailingLatitude', 50.1234567),
                    ('PersonMailingLongitude', 103.1234567),
                    ('PersonMailingGeocodeAccuracy', 'Address'),
                ])),
            ]),
            OrderedDict([
                ('attributes', OrderedDict([('type', 'Account'),
                 ('url', '/services/data/v1.0/sobjects/Account/TEST002')])),
                ('Id', 'TEST002'),
                ('AccountNumber', 'test002'),
                ('LastModifiedDate', '2022-06-01T00:00:00.000+0000'),
                ('LastModifiedById', 1.23E+0),
                ('SystemModstamp', '2022-06-01T00:00:00.000+0000'),
                ('IsDeleted', False),
                ('PersonMailingAddress', OrderedDict([
                    ('PersonMailingStreet', 'Lorem ipsum dolor sit amet, \nconsectetur adipiscing elit, \nsed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'),  # noqa: E501
                    ('PersonMailingCity', 'New york city'),
                    ('PersonMailingState', 'Ohaio'),
                    ('PersonMailingPostalCode', '999-9999'),
                    ('PersonMailingCountry', 'US'),
                    ('PersonMailingLatitude', 50.1234567),
                    ('PersonMailingLongitude', 103.1234567),
                    ('PersonMailingGeocodeAccuracy', 'Address'),
                ])),
            ]),
            OrderedDict([
                ('attributes', OrderedDict([('type', 'Account'),
                 ('url', '/services/data/v1.0/sobjects/Account/TEST003')])),
                ('Id', 'TEST003'),
                ('AccountNumber', 'test003'),
                ('LastModifiedDate', '2022-06-01T00:00:00.000+0000'),
                ('LastModifiedById', 1.234567),
                ('SystemModstamp', '2022-06-01T00:00:00.000+0000'),
                ('IsDeleted', False),
                ('PersonMailingAddress', OrderedDict([
                    ('PersonMailingStreet', 'Lorem ipsum dolor sit amet, \nconsectetur adipiscing elit, \nsed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'),  # noqa: E501
                    ('PersonMailingCity', 'New york city'),
                    ('PersonMailingState', 'Ohaio'),
                    ('PersonMailingPostalCode', '999-9999'),
                    ('PersonMailingCountry', 'US'),
                    ('PersonMailingLatitude', 50.1234567),
                    ('PersonMailingLongitude', 103.1234567),
                    ('PersonMailingGeocodeAccuracy', 'Address'),
                ])),
            ]),
        ]

        target_object_dict = {
            'object_name': 'Account',
            'columns': [
                'Id',
                'AccountNumber',
                'LastModifiedDate',
                'LastModifiedById',
                'SystemModstamp',
                'IsDeleted',
                'PersonMailingAddress'
            ]
        }

        execute_datetime = ExecuteDateTime()
        target_object = TargetObject(target_object_dict, execute_datetime)

        # Act
        actual_csv_data = convert_crm_csv_data_process(target_object, response_json)

        # Assert

        expect_csv_data = [
            ["Id", "AccountNumber", "LastModifiedDate", "LastModifiedById", "SystemModstamp", "IsDeleted", "PersonMailingAddress"],
            ["TEST001", "test001", "2022-06-01 09:00:00", 1234567.0, "2022-06-01 09:00:00", 1,
                "{\"PersonMailingStreet\": \"Lorem ipsum dolor sit amet, \\nconsectetur adipiscing elit, \\nsed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\", \"PersonMailingCity\": \"New york city\", \"PersonMailingState\": \"Ohaio\", \"PersonMailingPostalCode\": \"999-9999\", \"PersonMailingCountry\": \"US\", \"PersonMailingLatitude\": 50.1234567, \"PersonMailingLongitude\": 103.1234567, \"PersonMailingGeocodeAccuracy\": \"Address\"}"],
            ["TEST002", "test002", "2022-06-01 09:00:00", 1.23, "2022-06-01 09:00:00", 0,
                "{\"PersonMailingStreet\": \"Lorem ipsum dolor sit amet, \\nconsectetur adipiscing elit, \\nsed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\", \"PersonMailingCity\": \"New york city\", \"PersonMailingState\": \"Ohaio\", \"PersonMailingPostalCode\": \"999-9999\", \"PersonMailingCountry\": \"US\", \"PersonMailingLatitude\": 50.1234567, \"PersonMailingLongitude\": 103.1234567, \"PersonMailingGeocodeAccuracy\": \"Address\"}"],
            ["TEST003", "test003", "2022-06-01 09:00:00", 1.234567, "2022-06-01 09:00:00", 0,
                "{\"PersonMailingStreet\": \"Lorem ipsum dolor sit amet, \\nconsectetur adipiscing elit, \\nsed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\", \"PersonMailingCity\": \"New york city\", \"PersonMailingState\": \"Ohaio\", \"PersonMailingPostalCode\": \"999-9999\", \"PersonMailingCountry\": \"US\", \"PersonMailingLatitude\": 50.1234567, \"PersonMailingLongitude\": 103.1234567, \"PersonMailingGeocodeAccuracy\": \"Address\"}"],
        ]
        # 返り値の期待値チェック
        assert isinstance(actual_csv_data, list), 'CSVのリストが返却される'
        assert actual_csv_data == expect_csv_data

        # ログの確認
        assert generate_log_message_tuple(log_message='I-CONV-01 [Account] のCSV変換処理を開始します') in caplog.record_tuples
        assert generate_log_message_tuple(log_message='I-CONV-03 [Account] のCSV変換処理を終了します') in caplog.record_tuples

    def test_call_depended_modules(self):
        """
        Cases:
            CSV変換処理内で依存しているモジュールが正しく呼ばれていること
        Arranges:
            - CSV変換処理の依存モジュールをモック化する
        Expects:
            - 依存しているモジュールが正しく呼ばれている
        """

        # Arrange
        target_object_dict = {
            'object_name': 'Account',
            'columns': [
                'Id',
                'AccountNumber',
                'LastModifiedDate',
                'LastModifiedById',
                'SystemModstamp',
                'IsDeleted'
            ]
        }

        execute_datetime = ExecuteDateTime()
        target_object = TargetObject(target_object_dict, execute_datetime)
        # Act
        with patch('src.convert_crm_csv_data_process.CSVStringConverter') as mock_converter:
            inst = mock_converter.return_value
            inst.convert.return_value = ''
            convert_crm_csv_data_process(target_object, {})

        # Assert
        assert mock_converter.called is True
        assert inst.convert.called is True

    def test_raise_convert(self):
        """
        Cases:
            CSV変換処理でエラーが発生した場合、検査例外が発生すること
        Arranges:
            - CSV変換処理で例外が発生するようにする
        Expects:
            - 例外が発生する
            - 形式チェックが失敗したエラーが返却される
        """

        # Arrange
        target_object_dict = {
            'object_name': 'Account',
            'columns': [
                'Id',
                'AccountNumber',
                'LastModifiedDate',
                'LastModifiedById',
                'SystemModstamp',
                'IsDeleted'
            ]
        }

        execute_datetime = ExecuteDateTime()
        target_object = TargetObject(target_object_dict, execute_datetime)
        # Act
        with patch('src.convert_crm_csv_data_process.CSVStringConverter') as mock_converter:
            inst = mock_converter.return_value
            inst.convert.side_effect = Exception('変換エラー')
            with pytest.raises(DataConvertException) as e:
                convert_crm_csv_data_process(target_object, {})

        # Assert
        assert mock_converter.called is True
        assert inst.convert.called is True

        assert e.value.error_id == 'E-CONV-01'
        assert e.value.func_name == CONV_JP_NAME
        assert e.value.args[0] == f'[Account] CSV変換に失敗しました エラー内容:[変換エラー]'
