import os
import pytest
import shutil
from calculate.templates.format.base_format import FormatError
from calculate.templates.format.backgrounds_format import BackgroundsFormat
from calculate.templates.template_engine import ParametersContainer
from calculate.variables.datavars import NamespaceNode, VariableNode, ListType


datavars = NamespaceNode("<root>")
datavars.add_namespace(NamespaceNode("main"))
VariableNode("cl_resolutions", datavars.main, ListType,
             source=["1024x768"])


TMP_BACKUP_DIR = 'tests/templates/format/testfiles/backgrounds/tmp.backup'
TMP_DIR = 'tests/templates/format/testfiles/backgrounds/tmp'


@pytest.mark.backgrounds
def test_make_tmp_dir():
    if not os.path.exists(TMP_DIR):
        shutil.copytree(TMP_BACKUP_DIR, TMP_DIR)


@pytest.mark.backgrounds
@pytest.mark.parametrize('case', [
        {
            "id": "PNG -> PNG",
            "source":
            'tests/templates/format/testfiles/backgrounds/picture_0.png',
            "convert": False,
            "stretch": True,
            "target": 'result_0-',
            "template_text": ("original\n1024x768"),
            "result": ("PNG", ["32x16", "1024x768"]),
        },
        {
            "id": "JPEG -> JPEG",
            "source":
            'tests/templates/format/testfiles/backgrounds/picture_1.jpg',
            "convert": False,
            "stretch": True,
            "target": 'result_1-',
            "template_text": ("original\n1024x768"),
            "result": ("JPEG", ["320x180", "1024x768"]),
        },
        {
            "id": "PNG -> JPEG",
            "source":
            'tests/templates/format/testfiles/backgrounds/picture_0.png',
            "convert": "JPEG",
            "stretch": True,
            "target": "result_2-",
            "template_text": ("320x160\n1024x768"),
            "result": ("JPEG", ["320x160", "1024x768"]),
        },
        {
            "id": "PNG -> GIF",
            "source":
            'tests/templates/format/testfiles/backgrounds/picture_0.png',
            "convert": "GIF",
            "stretch": True,
            "target": "result_3-",
            "template_text": ("320x160\n1024x768"),
            "result": ("GIF", ["320x160", "1024x768"]),
        },
        pytest.param(
            {
                "id": "JPEG -> PNG",
                "source":
                'tests/templates/format/testfiles/backgrounds/picture_1.jpg',
                "convert": "PNG",
                "stretch": True,
                "target": "result_4-",
                "template_text": ("640x360\n1024x768"),
                "result": ("PNG", ["640x360", "1024x768"]),
            },
            marks=pytest.mark.backgrounds_slow
        ),
        {
            "id": "JPEG -> GIF",
            "source":
            'tests/templates/format/testfiles/backgrounds/picture_1.jpg',
            "convert": "GIF",
            "stretch": True,
            "target": "result_5-",
            "template_text": ("original\n1024x768"),
            "result": ("GIF", ["320x180", "1024x768"]),
        },
        {
            "id": "JPEG -> GFXBOOT(JPEG)",
            "source":
            'tests/templates/format/testfiles/backgrounds/picture_1.jpg',
            "convert": "GFXBOOT",
            "stretch": False,
            "target": "result_6-",
            "template_text": ("original\n200x100"),
            "result": ("JPEG", ["320x180", "200x100"]),
        },
        {
            "id": "PNG -> JPEG (single from template)",
            "source":
            'tests/templates/format/testfiles/backgrounds/picture_0.png',
            "convert": "JPEG",
            "stretch": True,
            "target": "result_7",
            "template_text": ("320x160"),
            "result": ("JPEG", ["320x160"]),
        },
        {
            "id": "JPEG -> JPEG (single from variable)",
            "source":
            'tests/templates/format/testfiles/backgrounds/picture_1.jpg',
            "convert": False,
            "stretch": True,
            "target": "result_8-",
            "template_text": "",
            "result": ("JPEG", ["1024x768"]),
        },
    ],
    ids=lambda x: x["id"])
def test_resize_and_convert_of_different_formats(case):
    target_path = os.path.join(TMP_DIR, case["target"])
    parameters = ParametersContainer({'source': case["source"],
                                      'convert': case["convert"],
                                      'stretch': case["stretch"]})
    backgrounds_object = BackgroundsFormat(case["template_text"],
                                           "path/to/template",
                                           parameters, datavars)
    changed_files = backgrounds_object.execute_format(target_path)

    images_format, resolutions = case["result"]

    output_paths = []
    if len(resolutions) > 1 or not case['template_text']:
        for resolution in resolutions:
            output_paths.append("{}{}.{}".format(target_path, resolution,
                                                 images_format.lower()))
    elif len(resolutions) == 1:
        resolution = next(iter(resolutions))
        output_paths.append(target_path)

    for outpath in output_paths:
        assert os.path.exists(outpath)
        assert backgrounds_object._magician.get_image_format(outpath
                                                             ) == images_format

    # print("CHANGED FILES:")
    # for path, status in changed_files.items():
    #     print(f"{path} -> {status}")
    # assert False


@pytest.mark.backgrounds
@pytest.mark.parametrize('case', [
        {
            "id": "stretch off",
            "source":
            'tests/templates/format/testfiles/backgrounds/picture_1.jpg',
            "convert": False,
            "stretch": False,
            "target": 'result_8-',
            "template_text": ("400x200\n30x10"),
            "result": {"400x200": False, "30x10": True},
        },
        {
            "id": "stretch on",
            "source":
            'tests/templates/format/testfiles/backgrounds/picture_1.jpg',
            "convert": False,
            "stretch": True,
            "target": 'result_9-',
            "template_text": ("400x200\n30x10"),
            "result": {"400x200": True, "30x10": True},
        },
    ],
    ids=lambda x: x["id"])
def test_scretch_parameter(case):
    target_path = os.path.join(TMP_DIR, case["target"])
    parameters = ParametersContainer({'source': case["source"],
                                      'convert': case["convert"],
                                      'stretch': case["stretch"]})
    backgrounds_object = BackgroundsFormat(case["template_text"],
                                           "path/to/template",
                                           parameters, datavars)
    changed_files = backgrounds_object.execute_format(target_path)

    for resolution, result in case["result"].items():
        image_path = "{}{}.jpeg".format(target_path, resolution)
        assert os.path.exists(image_path) is result
        if result:
            width, height = resolution.split("x")
            assert backgrounds_object._magician.get_image_resolution(
                                                      image_path) == (
                                                                   int(width),
                                                                   int(height))


# @pytest.mark.backgrounds
# def test_to_create():
#     target_path = os.path.join(TMP_BACKUP_DIR, "result_13-")
#     source_path = 'tests/templates/format/testfiles/backgrounds/picture_2.png'
#     parameters = ParametersContainer({'source': source_path,
#                                       'convert': False,
#                                       'stretch': False})
#     backgrounds_object = BackgroundsFormat("1650x1050\n1024x768",
#                                            "path/to/template",
#                                            parameters, datavars)
#     backgrounds_object.execute_format(target_path)


@pytest.mark.backgrounds
def test_if_template_has_been_already_used__it_will_not_be_reused():
    target_path = os.path.join(TMP_DIR, "result_10-")
    source_path = 'tests/templates/format/testfiles/backgrounds/picture_2.png'
    parameters = ParametersContainer({'source': source_path,
                                      'convert': False,
                                      'stretch': False})
    backgrounds_object = BackgroundsFormat("1650x1050\n1024x768",
                                           "path/to/template",
                                           parameters, datavars)
    changed_files = backgrounds_object.execute_format(target_path)
    assert not changed_files


@pytest.mark.backgrounds_slow
@pytest.mark.backgrounds
def test_if_template_is_using_in_directory_but_other_template_has_been_already_used_for_the_same_image_name__latest_template_will_remove_old_images_and_md5sum_file_and_create_new_ones():
    target_path = os.path.join(TMP_DIR, "result_11-")
    source_path = 'tests/templates/format/testfiles/backgrounds/picture_2.png'
    parameters = ParametersContainer({'source': source_path,
                                      'convert': False,
                                      'stretch': False})
    backgrounds_object = BackgroundsFormat("1440x1080\n1280x960",
                                           "path/to/template",
                                           parameters, datavars)
    changed_files = backgrounds_object.execute_format(target_path)
    assert not os.path.exists(f"{target_path}1650x1050.png")
    assert os.path.exists(f"{target_path}1440x1080.png")
    assert os.path.exists(f"{target_path}1280x960.png")
    assert not os.path.exists(f"{target_path}1024x768.png")

    assert changed_files == {f"{target_path}1650x1050.png": "D",
                             f"{target_path}1024x768.png": "D",
                             f"{target_path.strip('_-.')}.md5sum": "M",
                             f"{target_path}1440x1080.png": "N",
                             f"{target_path}1280x960.png": "N"}


@pytest.mark.backgrounds_slow
@pytest.mark.backgrounds
def test_if_template_is_using_in_directory_which_contains_md5sum_file_without_any_images__the_template_will_remove_md5sum_file_and_create_new_one_and_images():
    target_path = os.path.join(TMP_DIR, "result_12-")
    source_path = 'tests/templates/format/testfiles/backgrounds/picture_2.png'
    parameters = ParametersContainer({'source': source_path,
                                      'convert': False,
                                      'stretch': False})
    backgrounds_object = BackgroundsFormat("1440x1080\n1280x960",
                                           "path/to/template",
                                           parameters, datavars)
    changed_files = backgrounds_object.execute_format(target_path)
    assert os.path.exists(f"{target_path}1440x1080.png")
    assert os.path.exists(f"{target_path}1280x960.png")

    assert changed_files == {f"{target_path.strip('_-.')}.md5sum": "M",
                             f"{target_path}1440x1080.png": "N",
                             f"{target_path}1280x960.png": "N"}


@pytest.mark.backgrounds_slow
@pytest.mark.backgrounds
def test_if_template_is_using_in_directory_which_contains_some_image_files_without_md5sum_file__the_template_will_remove_all_images_and_create_new_ones_and_new_md5sum_file():
    target_path = os.path.join(TMP_DIR, "result_13-")
    source_path = 'tests/templates/format/testfiles/backgrounds/picture_2.png'
    parameters = ParametersContainer({'source': source_path,
                                      'convert': False,
                                      'stretch': False})
    backgrounds_object = BackgroundsFormat("1440x1080\n1280x960",
                                           "path/to/template",
                                           parameters, datavars)
    changed_files = backgrounds_object.execute_format(target_path)
    assert not os.path.exists(f"{target_path}1650x1050.png")
    assert os.path.exists(f"{target_path}1440x1080.png")
    assert os.path.exists(f"{target_path}1280x960.png")
    assert not os.path.exists(f"{target_path}1024x768.png")

    assert changed_files == {f"{target_path}1650x1050.png": "D",
                             f"{target_path}1024x768.png": "D",
                             f"{target_path.strip('_-.')}.md5sum": "N",
                             f"{target_path}1440x1080.png": "N",
                             f"{target_path}1280x960.png": "N"}


@pytest.mark.backgrounds
def test_if_template_s_name_parameter_is_the_empty_line_and_its_text_contents_two_or_more_resolution_values__the_output_files_name_will_contains_its_resolutions_only():
    target_path = os.path.join(TMP_DIR, "result_14-")
    source_path = 'tests/templates/format/testfiles/backgrounds/picture_1.jpg'
    parameters = ParametersContainer({'source': source_path,
                                      'convert': False,
                                      'stretch': False,
                                      'name': ''})
    backgrounds_object = BackgroundsFormat("100x100\n60x60",
                                           "path/to/template",
                                           parameters, datavars)
    backgrounds_object.execute_format(target_path)

    assert os.path.exists(os.path.join(TMP_DIR, "100x100.jpeg"))
    assert os.path.exists(os.path.join(TMP_DIR, "60x60.jpeg"))
    assert os.path.exists(os.path.join(TMP_DIR, "md5sum"))


@pytest.mark.backgrounds
def test_if_template_s_name_parameter_is_the_empty_line_and_its_text_contents_one_resolution_value__the_format_will_raise_FormatError_exception():
    target_path = os.path.join(TMP_DIR, "result_15-")
    source_path = 'tests/templates/format/testfiles/backgrounds/picture_1.jpg'
    parameters = ParametersContainer({'source': source_path,
                                      'convert': False,
                                      'stretch': False,
                                      'name': ''})
    backgrounds_object = BackgroundsFormat("100x100",
                                           "path/to/template",
                                           parameters, datavars)
    with pytest.raises(FormatError):
        backgrounds_object.execute_format(target_path)


@pytest.mark.backgrounds
def test_remove_tmp():
    if os.path.exists(TMP_DIR):
        shutil.rmtree(TMP_DIR)
