# -*- coding: utf-8 -*-
from multiprocessing import cpu_count
from dataclasses import dataclass, field

from pandas_ta._typing import Int, List
from pandas_ta.utils._time import get_time

__all__ = [
    'Study',
    'AllStudy',
    'CommonStudy',
    'Strategy',
    'AllStrategy',
    'CommonStrategy',
]


# Study DataClass
@dataclass
class Study:
    """Study DataClass
    Class to name and group indicators for processing

    Args:
        name (str): Some short memorable string.
            Note: Case-insensitive "All" is reserved.
        ta (list of dicts): A list of dicts containing keyword arguments
            where "kind" is the indicator.
        cores (int): The number cores to use for the study().
            Default: cpu_count()
        description (str): A more detailed description of what the Study
            tries to capture. Default: None
        created (str): At datetime string of when it was created.
            Default: Automatically generated. *Subject to change*

    Example TA:
    ta = [
        {"kind": "sma", "length": 200},
        {"kind": "sma", "close": "volume", "length": 50},
        {"kind": "bbands", "length": 20},
        {"kind": "rsi"},
        {"kind": "macd", "fast": 8, "slow": 21},
        {"kind": "sma", "close": "volume", "length": 20, "prefix": "VOLUME"},
    ],
    """
    name: str  # = None # Required.
    ta: List = field(default_factory=list)  # Required.
    cores: Int  = cpu_count()  # Number of cores. Default cpu_count()
    description: str = ""  # Helpful. More descriptive version or notes or w/e.
    # Optional. Gets Exchange Time and Local Time execution time
    created: str = get_time(to_string=True)

    def __post_init__(self):
        if isinstance(self.cores, int) and self.cores >= 0 and self.cores <= cpu_count():
            self.cores = int(self.cores)

        req_args = ["[X] Study requires the following argument(s):"]

        if self._is_name():
            req_args.append(
                ' - name. Must be a string. Example: "My TA". Note: "all" is reserved.')

        if self.ta is None:
            self.ta = None
        elif not self._is_ta():
            s = " - ta. Format is a list of dicts. Example: [{'kind': 'sma', 'length': 10}]"
            s += "\n       Check the indicator for the correct arguments if you receive this error."
            req_args.append(s)

        if len(req_args) > 1:
            [print(_) for _ in req_args]
            return None

    def _is_name(self):
        return self.name is None or not isinstance(self.name, str)

    def _is_ta(self):
        if isinstance(self.ta, list) and self.total_ta() > 0:
            # Check that all elements of the list are dicts.
            # Does not check if the dicts values are valid indicator kwargs
            # User must check indicator documentation for all indicators args.
            return all([isinstance(_, dict) and len(
                _.keys()) > 0 for _ in self.ta])
        return False

    def total_ta(self):
        return len(self.ta) if self.ta is not None else 0


# All Study
AllStudy = Study(
    name="All",
    description="All the indicators with their default settings. Pandas TA default.",
    ta=None,
)

# Default (Example) Study.
CommonStudy = Study(
    name="Common Price and Volume SMAs",
    description="Common Price SMAs: 10, 20, 50, 200 and Volume SMA: 20.",
    cores=0,
    ta=[
        {"kind": "sma", "length": 10},
        {"kind": "sma", "length": 20},
        {"kind": "sma", "length": 50},
        {"kind": "sma", "length": 200},
        {"kind": "sma", "close": "volume", "length": 20, "prefix": "VOL"}
    ]
)

# Temporary Strategy DataClass Alias
Strategy = Study
AllStrategy = AllStudy
CommonStrategy = CommonStudy
