import os
import textwrap

import pytest
from src.writer.file_writer import CsvWriter, FileWriter, JsonWriter


class ConcreteFileWriter(FileWriter):
    def write(self) -> str:
        return super().write()


class ConcreteFileWriterAbstractMethodNotImplemented(FileWriter):
    pass


class TestFileWriter:

    def test_concrete_file_writer_instance_create(self):
        concrete_file_writer = ConcreteFileWriter('', '')
        assert isinstance(concrete_file_writer, FileWriter)

    def test_concrete_file_writer_call_write_method(self):
        concrete_file_writer = ConcreteFileWriter('', '')
        concrete_file_writer.write()

    def test_raise_abstract_class_do_not_create_instance(self):
        with pytest.raises(TypeError):
            FileWriter('', '')

    def test_raise_concrete_file_writer_not_implemented_abstract_method(self):
        with pytest.raises(TypeError):
            ConcreteFileWriterAbstractMethodNotImplemented('', '')


class TestJsonFileWriter:

    def test_write(self, tmpdir):
        """
        Cases:
            JSONファイルが書き込めること
        Arranges:

        Expects:
            JSONファイルが正しく書き込まれている
        """
        # Arrange
        file_name = 'test.json'
        file_path = os.path.join(tmpdir, file_name)
        content = {'test': 'テスト'}

        # Act
        sut = JsonWriter(file_path, content)
        sut.write()

        # Assert
        with open(file_path) as f:
            actual = f.read()

        assert actual == '{"test": "テスト"}'

    def test_raise_write_cause_file_path_not_exists(self):
        """
        Cases:
            書き込み先が存在しない場合エラーとなること
        Arranges:

        Expects:
            エラーが発生する
        """
        # Arrange
        file_name = 'test.json'
        file_path = os.path.join('invalid', file_name)
        content = {'test': 'テスト'}

        # Act
        sut = JsonWriter(file_path, content)
        with pytest.raises(Exception):
            sut.write()


class TestCsvFileWriter:

    def test_write(self, tmpdir):
        """
        Cases:
            CSVファイルが書き込めること
        Arranges:

        Expects:
            CSVファイルが正しく書き込まれている
        """
        # Arrange
        file_name = 'test.csv'
        file_path = os.path.join(tmpdir, file_name)
        content = [
            ["Id", "AccountId", "UserOrGroupId", "AccountAccessLevel", "OpportunityAccessLevel", "CaseAccessLevel",
                "ContactAccessLevel", "RowCause", "LastModifiedDate", "LastModifiedById", "IsDeleted"],
            ["TEST001", "test001", "", 1, 2, 3, 4, "テストのため1", "2022-06-01 09:00:00", 1234567.0, 0],
            ["TEST002", "test002", "", 5, 6, 7, 8, "テストのため2", "2022-06-03 01:30:30", 2.23, 1],
            ["TEST003", "test003", "", 9, 10, 11, 12, "テストのため3", "2022-06-04 08:50:50", 3.234567, 0]
        ]

        # Act
        sut = CsvWriter(file_path, content)
        sut.write()

        # Assert
        with open(file_path, newline='') as f:
            actual = f.read()

        expect = """\
            "Id","AccountId","UserOrGroupId","AccountAccessLevel","OpportunityAccessLevel","CaseAccessLevel","ContactAccessLevel","RowCause","LastModifiedDate","LastModifiedById","IsDeleted"\r\n\
            "TEST001","test001","","1","2","3","4","テストのため1","2022-06-01 09:00:00","1234567.0","0"\r\n\
            "TEST002","test002","","5","6","7","8","テストのため2","2022-06-03 01:30:30","2.23","1"\r\n\
            "TEST003","test003","","9","10","11","12","テストのため3","2022-06-04 08:50:50","3.234567","0"\r\n\
        """

        assert actual == textwrap.dedent(expect)

    def test_raise_write_cause_file_path_not_exists(self):
        """
        Cases:
            書き込み先が存在しない場合エラーとなること
        Arranges:

        Expects:
            エラーが発生する
        """
        # Arrange
        file_name = 'test.csv'
        file_path = os.path.join('invalid', file_name)
        content = {'test': 'テスト'}

        # Act
        sut = CsvWriter(file_path, content)
        with pytest.raises(Exception):
            sut.write()
