from typing import Dict, Callable

from approvaltests.core.reporter import Reporter
from approvaltests.core.comparator import Comparator
from approvaltests.file_approver import FileComparator
from approvaltests.core.namer import Namer
from approvaltests.scrubbers import combine_scrubbers


class FileOptions:
    def __init__(self, fields: Dict):
        self.fields = fields

    @property
    def file_extention(self) -> str:
        return self.fields.get("extension_with_dot", ".txt")

    def with_extension(
        self,
        extension_with_dot: str,
        *,  # enforce keyword arguments - https://www.python.org/dev/peps/pep-3102/,
        no_override=False
    ) -> "Options":
        if not extension_with_dot.startswith("."):
            extension_with_dot = "." + extension_with_dot
        if no_override and "extension_with_dot" in self.fields:
            extension_with_dot = self.fields["extension_with_dot"]
        return Options({**self.fields, **{"extension_with_dot": extension_with_dot}})


class Options:
    def __init__(self, fields: Dict = None):
        self.fields = fields or {}

    @property
    def reporter(self) -> Reporter:
        from approvaltests.reporters.default_reporter_factory import (
            get_default_reporter,
        )

        return self.fields.get("reporter", get_default_reporter())

    @property
    def comparator(self) -> Comparator:
        return self.fields.get("comparator", FileComparator())

    def with_comparator(self, comparator: Comparator) -> "Options":
        return Options({**self.fields, **{"comparator": comparator}})

    def scrub(self, data):
        if self.has_scrubber():
            return self.fields["scrubber_func"](data)
        return data

    def with_scrubber(self, scrubber_func: Callable[[str], str]) -> "Options":
        return Options({**self.fields, **{"scrubber_func": scrubber_func}})

    def add_scrubber(self, scrubber) -> "Options":
        if self.has_scrubber():
            scrubber = combine_scrubbers(self.fields["scrubber_func"], scrubber)
        return self.with_scrubber(scrubber)

    def has_scrubber(self):
        return "scrubber_func" in self.fields

    def with_reporter(self, reporter: "Reporter") -> "Options":
        return Options({**self.fields, **{"reporter": reporter}})

    def with_namer(self, namer: "Namer") -> "Options":
        return Options({**self.fields, **{"namer": namer}})

    @property
    def for_file(self) -> FileOptions:
        return FileOptions(self.fields)

    @property
    def namer(self) -> Namer:
        from approvaltests.namer.default_name import get_default_namer

        namer = self.fields.get("namer", get_default_namer())
        if hasattr(namer, "set_extension"):
            namer.set_extension(self.for_file.file_extention)
        return namer
