import re

from string import ascii_uppercase

from .. import BaseProvider, ElementsType

localized = True


def calculate_vin_str_weight(s: str, weight_factor: list) -> int:
    """
    multiply s(str) by weight_factor char by char
    e.g.
    input: s="ABCDE", weight_factor=[1, 2, 3, 4, 5]
    return: A*1 + B*2 + C*3 + D*4 + E*5

    will multiply 0 when len(weight_factor) less than len(s)
    """

    def _get_char_weight(c: str) -> int:
        """A=1, B=2, ...., I=9,
        J=1, K=2, ..., R=9,
        S=2, T=3, ..., Z=9
        """
        if ord(c) <= 64:  # 0-9
            return int(c)
        if ord(c) <= 73:  # A-I
            return ord(c) - 64
        if ord(c) <= 82:  # J-R
            return ord(c) - 73
        # S-Z
        return ord(c) - 81

    res = 0
    for i, c in enumerate(s):
        res += _get_char_weight(c) * weight_factor[i] if i < len(weight_factor) else 0
    return res


class Provider(BaseProvider):
    """Implement default automotive provider for Faker."""

    license_formats: ElementsType = ()

    def license_plate(self) -> str:
        """Generate a license plate."""
        temp = re.sub(
            r"\?",
            lambda x: self.random_element(ascii_uppercase),
            self.random_element(self.license_formats),
        )
        return self.numerify(temp)

    def vin(self) -> str:
        """Generate vin number."""
        vin_chars = "1234567890ABCDEFGHJKLMNPRSTUVWXYZ"  # I, O, Q are restricted
        front_part = self.bothify("????????", letters=vin_chars)
        rear_part = self.bothify("????####", letters=vin_chars)
        front_part_weight = calculate_vin_str_weight(front_part, [8, 7, 6, 5, 4, 3, 2, 10])
        rear_part_weight = calculate_vin_str_weight(rear_part, [9, 8, 7, 6, 5, 4, 3, 2])
        checksum = (front_part_weight + rear_part_weight) % 11
        checksum_char = "X" if checksum == 10 else str(checksum)
        return front_part + checksum_char + rear_part
