from typing import Type

import pandas as pd

from hamilton.data_quality.base import ValidationResult, DataValidator, BaseDefaultValidator


class SampleDataValidator1(BaseDefaultValidator):
    def __init__(self, equal_to: int, importance: str):
        super(SampleDataValidator1, self).__init__(importance=importance)
        self.equal_to = equal_to

    @classmethod
    def applies_to(cls, datatype: Type[Type]) -> bool:
        return datatype == int

    def description(self) -> str:
        return 'Data must be equal to 10 to be valid'

    @classmethod
    def name(cls) -> str:
        return 'dummy_data_validator_1'

    def validate(self, dataset: int) -> ValidationResult:
        passes = dataset == 10
        return ValidationResult(
            passes=passes,
            message=f"Data value: {dataset} {'does' if passes else 'does not'} equal {self.equal_to}"
        )

    @classmethod
    def arg(cls) -> str:
        return 'equal_to'

    def __eq__(self, other):
        return isinstance(other, self.__class__) and self.equal_to == other.equal_to


class SampleDataValidator2(DataValidator):
    def __init__(self, dataset_length: int, importance: str):
        super(SampleDataValidator2, self).__init__(importance=importance)
        self.dataset_length = dataset_length

    def description(self) -> str:
        return f'series must have length {self.dataset_length} to be valid'

    @classmethod
    def name(cls) -> str:
        return 'dummy_data_validator_2'

    def validate(self, dataset: pd.Series) -> ValidationResult:
        passes = len(dataset) == self.dataset_length
        return ValidationResult(
            passes=passes,
            message=f"Dataset length is: {len(dataset)}. This {'passes' if passes else 'does not pass'}. It must be exactly '{self.dataset_length}",
            diagnostics={'dataset_length_must_be': self.dataset_length, 'dataset_length_is': len(dataset)}
        )

    @classmethod
    def applies_to(cls, datatype: Type[Type]) -> bool:
        return datatype == pd.Series

    @classmethod
    def arg(cls) -> str:
        return 'dataset_length'

    def __eq__(self, other):
        return isinstance(other, self.__class__) and self.dataset_length == other.dataset_length


class SampleDataValidator3(DataValidator):
    def __init__(self, dtype: type, importance: str):
        super(SampleDataValidator3, self).__init__(importance=importance)
        self.dtype = dtype

    def description(self) -> str:
        return f'Series dtype must be {self.dtype} to be valid'

    @classmethod
    def name(cls) -> str:
        return 'dummy_data_validator_3'

    def validate(self, dataset: pd.Series) -> ValidationResult:
        passes = dataset.dtype == self.dtype
        return ValidationResult(
            passes=passes,
            message=f"Dataset type is: {dataset.dtype}. This {'passes' if passes else 'does not pass'}. It must be '{self.dtype}",
            diagnostics={'required_dtype': str(self.dtype), 'actual_dtype': str(dataset.dtype)}
        )

    @classmethod
    def applies_to(cls, datatype: Type[Type]) -> bool:
        return datatype == pd.Series

    @classmethod
    def arg(cls) -> str:
        return 'dtype'

    def __eq__(self, other):
        return isinstance(other, self.__class__) and self.dtype == other.dtype


DUMMY_VALIDATORS_FOR_TESTING = [
    SampleDataValidator1,
    SampleDataValidator2,
    SampleDataValidator3
]
