"""
Data Validator using Shapiro-Wilk test for normality
"""
import pandas as pd
import numpy as np
from scipy import stats
import json


class DataValidator:
    def __init__(self, data):
        """
        Initialize validator with synthetic data

        Parameters:
        - data: DataFrame with bid and ask columns
        """
        self.data = data
        self.results = {}

    def calculate_spread(self):
        """Calculate bid-ask spread"""
        self.spread = self.data['ask'] - self.data['bid']
        return self.spread

    def shapiro_wilk_test(self):
        """
        Perform Shapiro-Wilk test on bid-ask spread

        Returns normality assessment and statistics
        """
        spread = self.calculate_spread()

        # Shapiro-Wilk test (sample if too large)
        if len(spread) > 5000:
            test_sample = spread.sample(5000, random_state=42)
        else:
            test_sample = spread

        statistic, p_value = stats.shapiro(test_sample)

        # Interpretation
        alpha = 0.05
        is_normal = p_value > alpha

        self.results = {
            'test_name': 'Shapiro-Wilk',
            'statistic': float(statistic),
            'p_value': float(p_value),
            'alpha': alpha,
            'is_normal': bool(is_normal),
            'interpretation': 'Normal distribution' if is_normal else 'Not normal distribution',
            'sample_size': int(len(test_sample)),
            'spread_stats': {
                'mean': float(spread.mean()),
                'std': float(spread.std()),
                'min': float(spread.min()),
                'max': float(spread.max()),
                'median': float(spread.median())
            }
        }

        return self.results

    def generate_statistics(self):
        """Generate comprehensive statistics for the synthetic data"""
        stats_dict = {
            'data_points': int(len(self.data)),
            'bid_stats': {
                'mean': float(self.data['bid'].mean()),
                'std': float(self.data['bid'].std()),
                'min': float(self.data['bid'].min()),
                'max': float(self.data['bid'].max()),
                'median': float(self.data['bid'].median())
            },
            'ask_stats': {
                'mean': float(self.data['ask'].mean()),
                'std': float(self.data['ask'].std()),
                'min': float(self.data['ask'].min()),
                'max': float(self.data['ask'].max()),
                'median': float(self.data['ask'].median())
            }
        }

        return stats_dict

    def create_visualization_data(self):
        """Prepare data for visualization"""
        spread = self.calculate_spread()

        # Sample data for plotting (for performance)
        plot_sample_size = min(1000, len(self.data))
        plot_indices = np.linspace(0, len(self.data) - 1, plot_sample_size, dtype=int)

        viz_data = {
            'timestamps': [str(self.data.index[i]) for i in plot_indices],
            'bid': [float(self.data['bid'].iloc[i]) for i in plot_indices],
            'ask': [float(self.data['ask'].iloc[i]) for i in plot_indices],
            'spread': [float(spread.iloc[i]) for i in plot_indices],
            'spread_histogram': {
                'values': spread.tolist(),
                'bins': 50
            }
        }

        return viz_data

    def validate_and_report(self):
        """
        Run complete validation and return comprehensive report
        """
        # Run Shapiro-Wilk test
        test_results = self.shapiro_wilk_test()

        # Generate statistics
        stats = self.generate_statistics()

        # Prepare visualization data
        viz_data = self.create_visualization_data()

        # Combine all results
        report = {
            'validation': test_results,
            'statistics': stats,
            'visualization': viz_data,
            'timestamp': pd.Timestamp.now().isoformat()
        }

        return report


def validate_data(df):
    """Quick validation function"""
    validator = DataValidator(df)
    return validator.validate_and_report()


if __name__ == "__main__":
    # Test the validator
    print("Testing Data Validator...")

    # Create sample data
    np.random.seed(42)
    test_data = pd.DataFrame({
        'bid': np.random.normal(4000, 3, 1000),
        'ask': np.random.normal(4000.1, 3, 1000)
    })

    validator = DataValidator(test_data)
    report = validator.validate_and_report()

    print("\nValidation Results:")
    print(json.dumps(report['validation'], indent=2))
    print("\nStatistics:")
    print(json.dumps(report['statistics'], indent=2))
