"""
Provide various types of technologies for recognition
and normalization product descriptions.
"""
import os
import wget
from typing import Union, Optional, Dict
import pandas as pd  # type: ignore
try:
    from receipt_parser.finder import Finder
    from receipt_parser.normalizer import Normalizer
except ImportError:
    from finder import Finder
    from normalizer import Normalizer
except ModuleNotFoundError:
    from .finder import Finder
    from .normalizer import Normalizer


class DownloadData:

    def __init__(self):
        print("It's need to download some data...")
        self.files = {
            "cleaned/all_clean.csv": "https://raw.githubusercontent.com/slgero/receipt_parser/master/receipt_parser/data/cleaned/all_clean.csv",
            "cleaned/brands_en.csv": "https://raw.githubusercontent.com/slgero/receipt_parser/master/receipt_parser/data/cleaned/brands_en.csv",
            "cleaned/brands_ru.csv": "https://raw.githubusercontent.com/slgero/receipt_parser/master/receipt_parser/data/cleaned/brands_ru.csv",
            "cleaned/products.csv": "https://raw.githubusercontent.com/slgero/receipt_parser/master/receipt_parser/data/cleaned/products.csv",
            "blacklist.csv": "https://raw.githubusercontent.com/slgero/receipt_parser/master/receipt_parser/data/blacklist.csv"
        }
        self.home_folder = os.path.join(os.getcwd(), 'data')

    @staticmethod
    def _is_folder_exist() -> bool:
        pwd: str = os.getcwd()
        data_folder: str = os.path.join(pwd, 'data')
        return os.path.isdir(data_folder)

    @staticmethod
    def _make_dirs() -> None:
        os.makedirs('data')
        os.makedirs(os.path.join('data', 'cleaned'))
    
    def download_files(self) -> None:
        for name, url in self.files.items():
            print(f"Download {name.split('/')[-1]}")
            wget.download(url, os.path.join("data", name))

    def get_pathes(self) -> Dict[str, str]:
        pathes: Dict[str, str] = {}

        for path in self.files.keys():
            name = path.split("/")[-1].split(".")[0]
            pathes[name] = os.path.join(self.home_folder, path)
        return pathes
    
    def download(self):
        if not self._is_folder_exist():
            self._make_dirs()
            self.download_files()
        return self.get_pathes()


# pylint: disable=too-few-public-methods
class RuleBased:
    """
    Use rules based on regular expressions and
    keyword selective tools on marked datasets to
    recognize product descriptions.

    Parameters
    ----------
    pathes: Optional[Dict[str, str]] (default=None)
        Dictionary with paths to *.csv files.

    Attributes
    ----------
    norm: Normalizer
        Normalize product description: expand abbreviations,
        delete garbage words and characters for further recognition,
        remove english worlds, etc.
    find : Finder
        Search and recognize the name, category and brand of a product
        from its description.

    Examples
    --------
    >>> rules = RuleBased()
    >>> rules.parse(df['name'])
    """

    def __init__(self, pathes: Optional[Dict[str, str]] = None):
        download_pathes = DownloadData().download()
        pathes = pathes or download_pathes

        self.norm = Normalizer(pathes)
        self.find = Finder(pathes)

    @staticmethod
    def __transform_data(data: Union[pd.DataFrame, pd.Series, str]) -> pd.Series:
        """Transform data to pd.Series into the desired format."""

        if isinstance(data, pd.DataFrame):
            if "name" not in data.columns:
                raise ValueError(
                    "Столбец с описанием товара должен иметь название `name`."
                )
            return data["name"]
        return pd.Series(data, name="name")

    # pylint: disable=bad-continuation
    def parse(
        self, data: Union[pd.DataFrame, pd.Series, str], verbose: int = 0
    ) -> pd.DataFrame:
        """
        Start the parsing process.

        Parameters
        ----------
        data : Union[pd.DataFrame, pd.Series, str]
            Text column with a description of the products to parse.
        verbose: int (default=0)
            Set verbose to any positive number for verbosity.

        Returns
        -------
        pd.DataFrame
            Recognized product names, brands and product categories.
        """

        data = self.__transform_data(data)
        data = self.norm.normalize(data)
        data = self.find.find_all(data, verbose)
        return data
