import sys
import pandas as pd
import numpy as np
import math

def topsis():
    try :
        n = len(sys.argv)
        
        if n != 5:
            raise ValueError("Wrong number of arguments.")
        if not sys.argv[1].lower().endswith('.csv') or not sys.argv[4].lower().endswith('.csv'):
            raise ValueError("File format should be .csv")

        try:
            df = pd.read_csv(sys.argv[1])
        except:
            print("File not found.")
            quit()
        
        if(df.shape[1] <3):
            raise ValueError("Columns should be >= 3")
        
        if(len(sys.argv[2].split(',')) != len(sys.argv[3].split(','))):
            raise ValueError("Weights not equal to impacts.")

        i=0
        while i<len(sys.argv[3]):
            if sys.argv[3][i] not in ["+","-"]:
                raise ValueError("The impacts should be either '+'/'-'")                
            i+=2

        data=df.copy(deep=True)

        li=[]
        for i in range(1,len(data.columns)):
            li.append(pd.to_numeric(data.iloc[:,i], errors='coerce').notnull().all())
        
        if any(li) == False :
            raise ValueError("Values are non-numeric")
        
        for i in data.columns[1:]:
            total = (data[i]**2).sum()
            sqrt=math.sqrt(total)
            data[i]=data[i]/sqrt
        
        w=sys.argv[2]
        weights=w.split(',')
        weights = list(map(float, weights))

        for i in range(1,len(weights)+1):
            data[data.columns[i]]=data.iloc[:,i]*weights[i-1]

        i=sys.argv[3]
        impacts=i.split(',')
        
        ideal_best=[]
        ideal_worst=[]

        for i in range(1,len(impacts)+1):        
            if(impacts[i-1]=='+'):
                ideal_best.append(data.iloc[:,i].max())
                ideal_worst.append(data.iloc[:,i].min())
            elif(impacts[i-1]=='-') :
                ideal_best.append(data.iloc[:,i].min())
                ideal_worst.append(data.iloc[:,i].max())

        dist_best=[]
        dist_worst=[]
        for i in data.index:    
            row_values=data.iloc[i,1:]
            diff=list(np.array(row_values) - np.array(ideal_best))
            squared = [number ** 2 for number in diff]
            dist_best.append(math.sqrt(sum(squared)))
            diff=list(np.array(row_values) - np.array(ideal_worst))
            squared = [number ** 2 for number in diff]
            dist_worst.append(math.sqrt(sum(squared)))
        
        performance=[]
        for i in data.index:
            performance.append(dist_worst[i]/(dist_best[i]+dist_worst[i]))
        
        df['Topsis Score']=performance
        df['Rank']=df['Topsis Score'].rank(method='dense', ascending=False)

        outputFilename=sys.argv[4]
        df.to_csv(outputFilename,index=False)

    except ValueError as e:
        print(e)

topsis()