import pathlib
from typing import Union,Tuple
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import re
import math

class QuestionnaireAnalysis:
    """
    Reads and analyzes data generated by the questionnaire experiment.
    Should be able to accept strings and pathlib.Path objects.
    """

    def __init__(self, data_fname: Union[pathlib.Path, str]):
        self.data = None
        if type(data_fname)== str:
            self.data_fname= pathlib.Path(data_fname)
        else:
            self.data_fname= data_fname
        if not self.data_fname.is_file():
            raise  ValueError('file does not exist')



    def read_data(self):
        """Reads the json data located in self.data_fname into memory, to
        the attribute self.data.
        """
        self.data= pd.read_json(self.data_fname)

    def show_age_distrib(self):
        df= self.data
        ages = df['age'].to_numpy()
        edges = np.array([i*10 for i in range(11)])
        list_of_ages = plt.hist(ages,bins=edges)[0]
        plt.show()
        return  (list_of_ages,edges)
    def remove_rows_without_mail(self):

        df = self.data
        self.data =  df[df['email'].map(validEmail)]
        self.data = self.data.reset_index(drop=True)
        return self.data

    def fill_na_with_mean(self) -> Tuple[pd.DataFrame, np.ndarray]:
        df= self.data
        badRows = set()
        for index, row in df.iterrows():
            for i in range(1,6):
                if math.isnan(row['q{0}'.format(i)]):
                    badRows.add(index)
                    df['q{0}'.format(i)][index] = np.nanmean([row['q1'],row['q2'],row['q3'],row['q4'],row['q5']])
        return (df,np.array(list(badRows)))

    def score_subjects(self, maximal_nans_per_sub: int = 1) -> pd.DataFrame:
        df = self.data
        values = []
        for index, row in df.iterrows():
            count = 0
            for i in range(1,6):
                if math.isnan(row['q{0}'.format(i)]):
                    count +=1
            if count > maximal_nans_per_sub:
                values.append(None)
            else:
                values.append(int(np.nanmean([row['q1'],row['q2'],row['q3'],row['q4'],row['q5']])))
        df['score'] = values
        df['score'] = df['score'].astype(pd.UInt8Dtype())
        self.data = df
        return self.data

    def correlate_gender_age(self) -> pd.DataFrame:
        #index = pd.MultiIndex.from_arrays(self.data, names=('gender', 'age'))
        df = self.data[['gender', 'age','q1','q2','q3','q4','q5']]
        df.age = df.age.apply(lambda x: x > 40)
        df = df.set_index(['gender', 'age'])
        df = df.groupby(['gender', 'age']).mean()
        return df



def validEmail(email):
    regex = '.+@.+\..+'
    pattern = re.compile(regex)
    return re.match(pattern,email) is not None







