from ..core.base import BaseValidator
from ..core.result import ValidationResult
import random

class CPF(BaseValidator):
    """
    Validator for Brazilian CPF (Cadastro de Pessoas Físicas).
    """

    @classmethod
    def validate(cls, doc: str) -> bool:
        doc = cls.clean(doc)
        
        if len(doc) != 11:
            return False
            
        if doc == doc[0] * 11:
            return False

        # Calculate first digit
        sum_val = 0
        for i in range(9):
            sum_val += int(doc[i]) * (10 - i)
        
        remainder = sum_val % 11
        digit1 = 0 if remainder < 2 else 11 - remainder

        if int(doc[9]) != digit1:
            return False

        # Calculate second digit
        sum_val = 0
        for i in range(10):
            sum_val += int(doc[i]) * (11 - i)
            
        remainder = sum_val % 11
        digit2 = 0 if remainder < 2 else 11 - remainder

        return int(doc[10]) == digit2

    @classmethod
    def format(cls, doc: str) -> str:
        doc = cls.clean(doc)
        if len(doc) != 11:
            raise ValueError("CPF must have 11 digits")
        return f"{doc[:3]}.{doc[3:6]}.{doc[6:9]}-{doc[9:]}"

    @classmethod
    def generate(cls) -> str:
        """Generates a valid CPF."""
        digits = [random.randint(0, 9) for _ in range(9)]
        
        # First digit
        sum_val = sum(d * (10 - i) for i, d in enumerate(digits))
        remainder = sum_val % 11
        digit1 = 0 if remainder < 2 else 11 - remainder
        digits.append(digit1)
        
        # Second digit
        sum_val = sum(d * (11 - i) for i, d in enumerate(digits))
        remainder = sum_val % 11
        digit2 = 0 if remainder < 2 else 11 - remainder
        digits.append(digit2)
        
        cpf = "".join(map(str, digits))
        return cls.format(cpf)

    @classmethod
    def get_origin(cls, doc: str) -> str:
        """
        Returns the Fiscal Region of origin based on the 9th digit.
        """
        doc = cls.clean(doc)
        if not cls.validate(doc):
            return None
            
        digit = int(doc[8])
        regions = {
            1: "DF, GO, MS, MT, TO",
            2: "AC, AM, AP, PA, RO, RR",
            3: "CE, MA, PI",
            4: "AL, PB, PE, RN",
            5: "BA, SE",
            6: "MG",
            7: "ES, RJ",
            8: "SP",
            9: "PR, SC",
            0: "RS"
        }
        return regions.get(digit, "Unknown")

    @classmethod
    def get_validation_pattern(cls) -> str:
        return r"^\d{3}\.\d{3}\.\d{3}-\d{2}$"

    @classmethod
    def check(cls, doc: str) -> ValidationResult:
        clean_doc = cls.clean(doc)
        
        if len(clean_doc) != 11:
             return ValidationResult(False, "LENGTH_ERROR", "CPF must have 11 digits")
             
        if clean_doc == clean_doc[0] * 11:
             return ValidationResult(False, "INVALID_DIGITS", "CPF cannot have all digits equal")
             
        if not cls.validate(doc):
             return ValidationResult(False, "CHECKSUM_ERROR", "Invalid check digits")
             
        return ValidationResult(True)
