from typing import Optional


class ErrorMessage():
    """Error message

    Args:
        code (str): Error code.
        pk (str | optional): The instance's primary key that triggered the error. Defaults to None.
        value (str | optional): The instance's value that triggered the error. Defaults to None.
    """

    def __init__(self, code: str, pk: Optional[str] = None, value: Optional[str] = None):
        self.code = code.upper()
        self.pk = pk
        self.value = value

    @property
    def _codes(self) -> list:
        return [
            func
            for func in dir(self)
            if func.isupper() and
            callable(getattr(self, func)) and
            not func.startswith("__")
        ]

    @property
    def _messages(self) -> dict:
        return {code: getattr(self, code) for code in self._codes}

    @property
    def message(self) -> str:
        if not self._validate_code():
            raise ValueError(f"{self.code} not found")
        return self._messages[self.code]()

    @property
    def code(self) -> str:
        return self._code

    @code.setter
    def code(self, code: str) -> None:
        self._code = code.upper()

    def _validate_code(self) -> bool:
        return self.code in self._codes

    @property
    def pk(self) -> str:
        return self._pk

    @pk.setter
    def pk(self, pk: str) -> None:
        self._pk = pk

    @property
    def value(self) -> str:
        return self._value

    @value.setter
    def value(self, value: str) -> None:
        self._value = value

    """
        Excel File Structure Error Codes
    """

    def EXL00(self):
        return f"The provided file '{self.pk}' is not an excel(xlsx) file"

    def EFS01(self):
        return "The 'Growth media' sheet is missing. Please check the provided excel template."

    def EFS02(self):
        return "The 'Geographic origin' sheet is missing. Please check the provided excel template."

    def EFS03(self):
        return "The 'Literature' sheet is missing. Please check the provided excel template."

    def EFS04(self):
        return "The 'Sexual state' sheet is missing. Please check the provided excel template."

    def EFS05(self):
        return "The 'Strains' sheet is missing. Please check the provided excel template."

    def EFS06(self):
        return "The 'Ontobiotope' sheet is missing. Please check the provided excel template."

    def EFS07(self):
        return "The 'Markers' sheet is missing. Please check the provided excel template."

    def EFS08(self):
        return "The 'Genomic information' sheet is missing. Please check the provided excel template."
    
    def EFS09(self):
        return "The 'Version' sheet is missing. Please check the provided excel template."

    """
        Growth Media Error Codes
    """

    def GMD01(self):
        return "The 'Acronym' column is a mandatory field in the Growth Media sheet."

    def GMD02(self):
        return "The 'Acronym' column is empty or has missing values."

    def GMD03(self):
        return "The 'Description' column is a mandatory field in the Growth Media sheet. The column can not be empty."

    def GMD04(self):
        return f"The 'Description' for growth media with Acronym {self.pk} is missing."

    """
        Geographic Origin Error Codes
    """

    def GOD01(self):
        return "The 'ID' column is a mandatory field in the Geographic Origin sheet."

    def GOD02(self):
        return "The 'ID' column is empty or has missing values."

    def GOD03(self):
        return "The 'Country' column is a mandatory field in the Geographic Origin sheet. The column can not be empty."

    def GOD04(self):
        return f"The 'Country' for geographic origin with ID {self.pk} is missing."

    def GOD05(self):
        return f"The 'Country' for geographic origin with ID {self.pk} is incorrect."

    def GOD06(self):
        return f"The 'Locality' column is a mandatory field in the Geographic Origin sheet. The column can not be empty."

    def GOD07(self):
        return f"The 'Locality' for geographic origin with ID {self.pk} is missing."

    """
        Literature Error Codes
    """

    def LID01(self):
        return "The 'ID' column is a mandatory field in the Literature sheet."

    def LID02(self):
        return "The 'ID' column empty or missing values."

    def LID03(self):
        return "The 'Full reference' column is a mandatory field in the Literature sheet. The column can not be empty."

    #def LID04(self):
        #return f"The 'Full reference' for literature with ID {self.pk} is missing."

    def LID05(self):
        return "The 'Authors' column is a mandatory field in the Literature sheet. The column can not be empty."

    #def LID06(self):
        #return f"The 'Authors' for literature with ID {self.pk} is missing."

    def LID07(self):
        return "The 'Title' column is a mandatory field in the Literature sheet. The column can not be empty."

    #def LID08(self):
        #return f"The 'Title' for literature with ID {self.pk} is missing."

    def LID09(self):
        return "The 'Journal' column is a mandatory field in the Literature sheet. The column can not be empty."

    #def LID10(self):
        #return f"The 'Journal' for literature with ID {self.pk} is missing."

    def LID11(self):
        return "The 'Year' column is a mandatory field in the Literature sheet. The column can not be empty."

    def LID12(self,):
        return f"The 'Year' for literature with ID {self.pk} is missing."

    def LID13(self):
        return "The 'Volume' column is a mandatory field in the Literature sheet. The column can not be empty."

    def LID14(self):
        return f"The 'Volume' for literature with ID {self.pk} is missing."

    def LID15(self):
        return "The 'First page' column is a mandatory field. The column can not be empty."

    def LID16(self):
        return f"The 'First page' for literature with ID {self.pk} is missing."

    def LID17(self):
        return( f"There are four types of ways to fill in the 'Literature' sheet.",
                "1st- Columns 'ID' and 'DOI' must be obrigatory.",
                "2nd-Columns 'ID' and 'PMID' are obrigatory.",
                "3rd-Columns 'ID' and 'Full reference' are obrigatory.",
                "In the alternative of these three types of forms not being filled in, we have:",
                "4th-Columns 'ID', 'Authors', 'Title', 'Journal', 'Year', 'Volume', 'First page'.")
        
    def LID18(self):
        return "The 'PMID' column is a mandatory field. The column can not be empty."

    #def LID19(self):
        #return f"PMID for literature with ID {self.pk} is missing."
    
    def LID20(self):
        return "The 'DOI' column is a mandatory field. The column can not be empty."

    #def LID21(self):
        #return f"DOI for literature with ID {self.pk} is missing."

    """
        Strains Error Codes
    """
    def STD01(self):
        return "The 'accessionNumber' column is a mandatory field in the Strains sheet."

    def STD02(self):
        return "The 'accessionNumber' column is empty or has missing values."

    def STD03(self):
        return f"The 'accessionNumber' must be unique. The '{self.value}' is repeated."

    def STD04(self):
        return (f"The 'accessionNumber' {self.pk} is not according to the specification."
                " The value must be of the format '<Sequence of characters> <sequence of characters>'.")

    def STD05(self):
        return f"The 'useRestrictions' column is a mandatory field in the Strains Sheet. The column can not be empty."

    def STD06(self):
        return f"The 'useRestrictions' for strain with accessionNumber {self.pk} is missing."

    def STD07(self):
        return (f"The 'useRestrictions' for strain with accessionNumber {self.pk} is not according to the specification."
                f" Your value is {self.value} and the accepted values are 1, 2, 3.")

    def STD08(self):
        return f"The 'nagoyaConditions' column is a mandatory field in the Strains Sheet. The column can not be empty."

    def STD09(self):
        return f"The 'nagoyaConditions' for strain with accessionNumber {self.pk} is missing."

    def STD10(self):
        return (f"The 'nagoyaConditions' for strain with accessionNumber {self.pk} is not according to the specification."
                f" Your value is {self.value} and the accepted values are 1, 2, 3.")

    def STD11(self):
        return (f"The 'registeredCollection' for strain with accessionNumber {self.pk} is not according to specification."
                f" Your value is {self.value} and the accepted values are 1, 2, 3.")

    def STD12(self):
        return "The 'riskGroup' column is a mandatory field in the Strains Sheet. The column can not be empty."

    def STD13(self):
        return f"The 'riskGroup' for strain with accessionNumber {self.pk} is missing."

    def STD14(self):
        return (f"The 'riskGroup' for strain with accessionNumber {self.pk} is not according to specification."
                f" Your value is {self.value} and the accepted values are 1, 2, 3, 4.")

    def STD15(self):
        return (f"The 'dualUse' for strain with accessionNumber {self.pk} is not according to specification."
                f" Your value is {self.value} and the accepted values are 1, 2.")

    def STD16(self):
        return (f"The “euQuarantine” for strain with accessionNumber {self.pk} is not according to specification."
                f" Your value is {self.value} and the accepted values are 1, 2.")

    def STD17(self):
        return f"The 'organismType' column is a mandatory field in the Strains Sheet. The column can not be empty."

    def STD18(self):
        return f"The 'organismType' for strain with accessionNumber {self.pk} is missing."

    def STD19(self):
        return (f"The 'organismType' for strain with accessionNumber {self.pk} is not according to specification."
                f" Your value is {self.value} and the accepted values are 'Algae', 'Archaea', 'Bacteria', 'Cyanobacteria', "
                "'Filamentous Fungi',  'Phage', 'Plasmid', 'Virus', 'Yeast', 1, 2, 3, 4, 5, 6, 7, 8, 9.")

    def STD20(self):
        return f"The 'speciesName' column is a mandatory field in the Strains Sheet. The column can not be empty."

    def STD21(self):
        return f"The 'speciesName' for strain with accessionNumber {self.pk} is missing."

    def STD22(self):
        return f"The 'speciesName' for strain with accessionNumber {self.pk} is incorrect."

    def STD23(self):
        return (f"The 'hybrid' for strain with accessionNumber {self.pk} is not according to specification."
                f" Your value is {self.value} and the accepted values are 1, 2.")

    def STD24(self):
        return (f"The 'depositHistory' for strain with accessionNumber {self.pk} is incorrect."
                "The field includes entries separated by '<' meaning 'received from'."
                "Entries may include persons or CCs. The name of the CC should be followed by"
                "the month, when available, and year of the acquisition. Between parentheses,"
                "the strain designation or CC numbers and/or a name can also be entered when "
                "a name change has occurred.")

    def STD25(self):
        return (f"The 'depositDate' for strain with accessionNumber {self.pk} is incorrect."
                " The allowed formats are 'YYYY-MM-DD', 'YYYYMMDD', 'YYYYMM', and 'YYYY'.")

    def STD26(self):
        return (f"The 'accessionDate' for strain with accessionNumber {self.pk} is incorrect."
                " The allowed formats are 'YYYY-MM-DD', 'YYYYMMDD', 'YYYYMM', and 'YYYY'.")

    def STD27(self):
        return (f"The 'collectionDate' for strain with accessionNumber {self.pk} is incorrect."
                " The allowed formats are 'YYYY-MM-DD', 'YYYYMMDD', 'YYYYMM', and 'YYYY'.")

    def STD28(self):
        return (f"The 'isolationDate' for strain with accessionNumber {self.pk} is incorrect."
                " The allowed formats are 'YYYY-MM-DD', 'YYYYMMDD', 'YYYYMM', and 'YYYY'.")

    def STD29(self):
        return (f"The 'temperatureGrowthRange' for strain with accessionNumber {self.pk} is incorrect."
                " It must have two decimal numbers separated by ','")

    def STD30(self):
        return f"The 'temperatureGrowthRange' column is a mandatory field in the Strains Sheet. The column can not be empty."

    def STD31(self):
        return f"The 'temperatureGrowthRange' for strain with accessionNumber {self.pk} is missing."

    def STD32(self):
        return (f"The 'temperatureGrowthRange' for strain with accessionNumber {self.pk} is incorrect."
                " It must have two decimal numbers separated by ','.")

    def STD33(self):
        return ("The 'recommendedTemperature' column is a mandatory field in the Strains Sheet. The column can not be empty.")

    def STD34(self):
        return f"The 'recommendedTemperature' for strain with accessionNumber {self.pk} is missing."

    def STD35(self):
        return f"The value of 'recommendedTemperature' for strain with accessionNumber {self.pk} is not in the Growth Media Sheet."

    def STD36(self):
        return f"The 'supplyForms' column is a mandatory field in the Strains Sheet. The column can not be empty."

    def STD37(self):
        return f"The 'supplyForms' for strain with accessionNumber {self.pk} is missing."

    def STD38(self):
        return f"The value of 'supplyForms' for strain with accessionNumber {self.pk} is not in the Forms of Supply Sheet."

    def STD39(self):
        return (f"The 'geographicCoordinates' column for strain with accessionNumber {self.pk} is incorrect."
                "The allowed formats are two, three or four decimal numbers separated by ','. Moreover, the first number must be."
                "between [-90, 90], the second between [-180, 180], and the third and fourth refers to the precision and altitude, defined by decimal numbers." 
                "Put a question mark for lack of precision or altitude when one of them is missing. Leave the values blank when both are missing. ")

    def STD40(self):
        return (f"The 'country' column for strain with accessionNumber {self.pk} is incorrect."
                "The allowed formats are one decimal number between [-200, 8000].")
    def STD54(self):
        return (f"The 'country'column is a mandatory field in the Strains Sheet. The column can not be empty.")
    def STD55(self):
        return (f"The 'country' for strain with accessionNumber {self.pk} is missing.")

    def STD41(self):
        return f"The value of 'ontobiotopeTerms' for strain with accessionNumber {self.pk} is not in the Ontobiotope Sheet."

    def STD42(self):
        return (f"The 'gmo' for strain with accessionNumber {self.pk} is not according to specification."
                f" Your value is {self.value} and the accepted values are 1, 2")

    def STD43(self):
        return (f"The 'sexualState' for strain with accessionNumber {self.pk} is not according to specification."
                f" Your value is {self.value} and the accepted values are 'Mata', 'Matalpha', 'Mata/Matalpha', "
                "'Matb', 'Mata/Matb', 'MTLa', 'MTLalpha', 'MTLa/MTLalpha', 'MAT1-1', 'MAT1-2', 'MAT1', 'MAT2', 'MT+', 'MT-'")

    def STD44(self):
        return (f"The 'ploidy' for strain with accessionNumber {self.pk} is not according to specification."
                f" Your value is {self.value} and the accepted values are 0, 1, 2, 3, 4, 9")

    def STD45(self):
        msg = f"At least one of the values '{self.value}' of the literature field for strain {self.pk} are not in the literature sheet. "
        msg += "If the those values are Pubmed ids or DOIs, please ignore this messsage"
        return msg

    def STD46(self):
       return (f"The 'geographicOrigin' for strain with accessionNumber {self.pk} is not according to specification."
           f"The 'geographicOrigin' column must consist of the ID's associated with the Geographic origin sheet.")

    def STD47(self):
        return "The 'country' column is a mandatory field in the Strains sheet."

    def STD48(self):
        return "The 'country' column is empty or has missing values."

    def STD49(self):
        return (f"The “qps” for strain with accessionNumber {self.pk} is not according to specification."
            f" Your value is {self.value} and the accepted values are 1, 2.")
        
    def STD50(self):
        return (f"The “axenicCulture” for strain with accessionNumber {self.pk} is not according to specification."
        f" Your value is {self.value} and the accepted values are 'Axenic', 'Not axenic'.")    

    def STD51(self):
        return f"The 'mirriAccessionNumber' must be unique. The '{self.pk}' is repeated."
    
    def STD52(self): 
        return (f"The 'mirriAccessionNumber' for strain with accessionNumber {self.pk} is incorrect."
                " It must have the expression MIRRI followed by 7 digits")
    
    def STD53(self): 
        return (f"The 'siteLinks' for strain with accessionNumber {self.pk} is incorrect."
                " The displayed expression it should be composed of: site name ';' website url." )
    
    def STD56(self): 
        return (f"The 'siteLinks' for strain with accessionNumber {self.pk} is incorrect."
                " The url must be valid. " )    
    def STD57(self): 
        return (f"The 'country' for strain with accessionNumber {self.pk} is incorrect."
                "This information must be expressed by using the ISO-3166 standard for country" 
                "codes. The preferred set is ISO 3166-1 alpha-2 (two letters code), but ISO 3166-"
                "1 alpha-3 (three letters code) is also accepted. Former country codes must" 
                "follow standard’s part three ISO 3166-3 (four letters code). Only one code can" 
                "be included." )    
    def STD58(self): 
        return (f"The 'mtaFile' for strain with accessionNumber {self.pk} is incorrect."
                " The url must be valid. " )    
    def STD59(self): 
        return (f"The 'absFile' for strain with accessionNumber {self.pk} is incorrect."
                "The displayed expression it should be composed of: name ';' website url."
                "When only one URL is provided, the title may be omitted. In this case, the URL" 
                "will be shown in clear to users." ) 
    def STD60(self): 
        return (f"The 'absFile' for strain with accessionNumber {self.pk} is incorrect."
                 " The url must be valid. ")              
    def STD61(self): 
        return (f"The 'sequenceLiterature' for strain with accessionNumber {self.pk} is incorrect."
                 "Numeric identifiers separated by a semicolon ';'.")   
    
    def STD62(self): 
        return (f"The 'plasmidCollections' for strain with accessionNumber {self.pk} is incorrect."
                "It should include the name of the plasmid followed by the CC number in"
                "parentheses. More than one plasmid can be reported, separated by ';'. "
                "Plasmid names should be provided as free text."
                "CC numbers should be composed by the CC acronym followed by a number"
                "separated by a space'. Numeric identifiers separated by a semicolon ';'.")  
              
    def STD63(self): 
        return (f"The 'otherCollectionNumbers' for strain with accessionNumber {self.pk} is incorrect."
                " The value must be of the format '<Sequence of characters> <sequence of characters>'.")
        
    def STD64(self): 
        return (f"The 'type' for strain with accessionNumber {self.pk} is incorrect."
              f"Your value is {self.value} and the accepted values are 1, 2.")
        
    def STD65(self): 
        return (f"The 'status' for strain with accessionNumber {self.pk} is incorrect."
                "The structure should be 'type of <character string>.")
        
    def STD68(self):
        return (f"The 'geographicOrigin'column is a mandatory field in the Strains Sheet. The column can not be empty.")
    
    def STD69(self):
        return (f"The 'geographicOrigin' for strain with accessionNumber {self.pk} is missing.")
            
    """
        Genomic Information Error Codes
    """

    def GID01(self):
        return f"The 'Strain accessionNumber' (Strain AN) column is a mandatory field in the Genomic Information Sheet."

    def GID02(self):
        return f"The 'Strain accessionNumber' (Strain AN) column is empty or has missing values."

    def GID03(self):
        return f"The value of 'Strain accessionNumber' (Strain AN) {self.value} is not in the Strains sheet."

    def GID04(self):
        return f"The 'Marker' column is a mandatory field in the Genomic Information Sheet. The column can not be empty."

    def GID05(self):
        return f"The 'Marker' for genomic information with Strain AN {self.pk} is missing."

    def GID06(self):
        return f"The value of 'Marker' {self.value} is not in the Markers sheet."

    def GID07(self):
        return f"The 'INSDC AN' column is a mandatory field in the Genomic Information Sheet. The column can not be empty."

    def GID08(self):
        return f"The 'INSDC AN' for genomic information with Strain AN {self.pk} is missing."

    def GID09(self):
        return f"The 'INSDC AN' for genomic information with Strain AN {self.pk} is incorrect."

    def GID10(self):
        return (f"The 'Sequence' for genomic information with Strain AN {self.pk} is incorrect."
                " It must be a sequence of 'G', 'T', 'A', 'C' characteres of any length and without white spaces.")

    def GID11(self):
        return (f"The 'Sequence' for genomic information with Strain AN {self.pk} is incorrect."
                "An INSDC accession number is an alphanumeric"
                "code made by a fixed number of letters followed by a fixed number of digits," 
                "without any separation. For sequences, the code is currently made of two" 
                "letters followed by six numbers.")


    """
    Version Error Codes
    """

    def VRS01(self):
        return "The 'Version' columns is a mandatory field in the Version Sheet."

    def VRS02(self):
        return "The 'Version' columns is empty or has missing values."
    
    def VRS03(self):
        return "The 'Date' columns is a mandatory field in the Control Sheet."

    def VRS04(self):
        return "The 'Date' columns is empty or has missing values."

    def VRS05(self):
        return f"The version {self.value} is the only one to be used."



    """
        Ontobiotope Error Codes
    """

    def OTD01(self):
        return "The 'ID' columns is a mandatory field in the Ontobiotope Sheet."

    def OTD02(self):
        return "The 'ID' columns is empty or has missing values."

    #def OTD03(self):
        return "The 'Name' columns is a mandatory field in the Ontobiotope Sheet. The column can not be empty."

    #def OTD04(self):
        return f"The 'Name' for ontobiotope with ID {self.pk} is missing."

    

    