#https://bouquinpython.readthedocs.io/fr/latest/matrices.html
#https://www.bibmath.net/dico/index.php?action=affiche&quoi=./g/gausspivot.html
#https://github.com/learn-co-students/dsc-2-13-14-linalg-regression-codealong-online-ds-pt-100118?tab=readme-ov-file
#Intercept = moyenne(Y) - somme(des coefficients × moyennes(X)).

'''
https://medium.com/@bengikoseoglu/understanding-ordinary-least-square-in-matrix-form-with-r-b6cf2d08a93b coefficient de la matrice #β = (X'X)ˉ¹X'y
ou X' = transpose X
(X'X)ˉ¹ = inverse de X'X
β = (X'X)ˉ¹X'y

'''

import numpy as np
from classes.TW_Utility import TW_Utility
from sklearn.linear_model import LinearRegression
import statsmodels.api as sm


class TW_Matrice:
    def augmented_matrice(self, A, B):
        augmmentedMatrice = []
        if A.ndim > 3:
            raise Exception("3 Dimensions not supported")
        
        if A.ndim > B.ndim:
            for i in range(0,len(A)):
                row = np.append(A[i], B[i])
                augmmentedMatrice.append(row)
            augmmentedMatrice = np.array(augmmentedMatrice)
        else:
            augmmentedMatrice = np.hstack((A,B))

        return augmmentedMatrice
    
    def _reshape_in_square_form(self, M):
        nbrRows = len(M)
        nbrColumns = M.shape[len(M.shape) -1]
        nbrZeroPerRow = {}

        for i in range(0, nbrRows):
            for j in range(0, nbrColumns):
                if not TW_Utility.empty_or_none(nbrZeroPerRow, i):
                    nbrZeroPerRow[i] = 0

                if M[i][j] == 0:
                    nbrZeroPerRow[i] = nbrZeroPerRow[i] + 1

        nbrZeroPerRow = dict(sorted(nbrZeroPerRow.items(), key=lambda item: item[1]))
        return M[list(nbrZeroPerRow.keys())[:nbrColumns]]
        
    def reshape_matrice_in_square_form(self, M, strict = True):
        squareMatrice = self._reshape_in_square_form(M)

        if strict == False:
            return squareMatrice
        
        nbrRows = len(squareMatrice)
        for i in range(0, len(squareMatrice.shape)):
            if squareMatrice.shape[i] != nbrRows:
                return None

        return squareMatrice

    def sklearn_linear_regression(self, A, B):
        columnAdded = False
        regression = None

        try:
            regression = LinearRegression().fit(A, B)

        except:
            raise Exception("Try calling TW_Utility.adjust_series_nbr_columns")
        
        return regression
    
    def gaussian_system_linear_equation(self, A, B):
        coefficients = []
        constant = 0

        try:
            reg = LinearRegression().fit(A, B)
            coefficients = reg.coef_
            constant = reg.intercept_

        except:
            coefficients = []
            constant = 0
            raise Exception("Try calling TW_Utility.adjust_series_nbr_columns")

        return coefficients, constant
        

    def gaussian_system_exact_solution(self, A, B):
        A = A.astype('float64')
        B = B.astype('float64')

        solutions = []
        R = self.augmented_matrice(A,B)
        R = self.reshape_matrice_in_square_form(R, False)
        
        if not TW_Utility.empty_or_none(R):
            nbrColumns = R.shape[len(R.shape) -1]
            X = R[:, np.arange(nbrColumns -1)]
            Y = R[:, -1]

        solutions = np.linalg.solve(X, Y)
        return solutions if len(solutions) > 0 else None
    
    '''
    j'ai besoin de savoir si 2 plan, 3d ont une intersection
j'ai besoin de savoir ou se situent leur intersection
a l'intersection de 2 plans 3d se situe une droite (dont on peu calculer les coordonnées)
j'ai besoin de déterminer les coordonées x et y qui appartiennent au premier plan
et celles qui appartiennent au second plan pour pouvoir savoir sur quel segment je me situe
    '''