import string

from datetime import datetime

from .. import BaseProvider


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

    user_agents = (
        'chrome', 'firefox', 'internet_explorer', 'opera', 'safari',
    )

    windows_platform_tokens = (
        'Windows 95', 'Windows 98', 'Windows 98; Win 9x 4.90', 'Windows CE',
        'Windows NT 4.0', 'Windows NT 5.0', 'Windows NT 5.01',
        'Windows NT 5.1', 'Windows NT 5.2', 'Windows NT 6.0', 'Windows NT 6.1',
        'Windows NT 6.2',
    )

    linux_processors = ('i686', 'x86_64')

    mac_processors = ('Intel', 'PPC', 'U; Intel', 'U; PPC')

    android_versions = (
        '1.0', '1.1', '1.5', '1.6', '2.0', '2.0.1', '2.1', '2.2', '2.2.1', '2.2.2', '2.2.3', '2.3', '2.3.1', '2.3.2',
        '2.3.3', '2.3.4', '2.3.5', '2.3.6', '2.3.7', '3.0', '3.1', '3.2', '3.2.1', '3.2.2', '3.2.3', '3.2.4', '3.2.5',
        '3.2.6', '4.0', '4.0.1', '4.0.2', '4.0.3', '4.0.4', '4.1', '4.1.1', '4.1.2', '4.2', '4.2.1', '4.2.2', '4.3',
        '4.3.1', '4.4', '4.4.1', '4.4.2', '4.4.3', '4.4.4', '5.0', '5.0.1', '5.0.2', '5.1', '5.1.1', '6.0', '6.0.1',
        '7.0', '7.1', '7.1.1', '7.1.2', '8.0.0', '8.1.0', '9',
    )

    apple_devices = ('iPhone', 'iPad')

    ios_versions = (
        '3.1.3', '4.2.1', '5.1.1', '6.1.6', '7.1.2', '9.3.5', '9.3.6', '10.3.3', '10.3.4', '12.4',
    )

    def mac_processor(self):
        """Generate a MacOS processor token used in user agent strings."""
        return self.random_element(self.mac_processors)

    def linux_processor(self):
        """Generate a Linux processor token used in user agent strings."""
        return self.random_element(self.linux_processors)

    def user_agent(self):
        """Generate a random web browser user agent string."""
        name = self.random_element(self.user_agents)
        return getattr(self, name)()

    def chrome(self, version_from=13, version_to=63,
               build_from=800, build_to=899):
        """Generate a Chrome web browser user agent string."""
        saf = f'{self.generator.random.randint(531, 536)}.{self.generator.random.randint(0, 2)}'
        bld = self.lexify(self.numerify('##?###'), string.ascii_uppercase)
        tmplt = '({0}) AppleWebKit/{1} (KHTML, like Gecko)' \
                ' Chrome/{2}.0.{3}.0 Safari/{4}'
        tmplt_ios = '({0}) AppleWebKit/{1} (KHTML, like Gecko)' \
                    ' CriOS/{2}.0.{3}.0 Mobile/{4} Safari/{1}'
        platforms = (
            tmplt.format(self.linux_platform_token(),
                         saf,
                         self.generator.random.randint(version_from, version_to),
                         self.generator.random.randint(build_from, build_to),
                         saf),
            tmplt.format(self.windows_platform_token(),
                         saf,
                         self.generator.random.randint(version_from, version_to),
                         self.generator.random.randint(build_from, build_to),
                         saf),
            tmplt.format(self.mac_platform_token(),
                         saf,
                         self.generator.random.randint(version_from, version_to),
                         self.generator.random.randint(build_from, build_to),
                         saf),
            tmplt.format('Linux; {}'.format(self.android_platform_token()),
                         saf,
                         self.generator.random.randint(version_from, version_to),
                         self.generator.random.randint(build_from, build_to),
                         saf),
            tmplt_ios.format(self.ios_platform_token(),
                             saf,
                             self.generator.random.randint(version_from, version_to),
                             self.generator.random.randint(build_from, build_to),
                             bld),
        )

        return 'Mozilla/5.0 ' + self.random_element(platforms)

    def firefox(self):
        """Generate a Mozilla Firefox web browser user agent string."""
        ver = (
            (f'Gecko/{self.generator.date_time_between(datetime(2011, 1, 1))} '
             f'Firefox/{self.generator.random.randint(4, 15)}.0'),
            (f'Gecko/{self.generator.date_time_between(datetime(2010, 1, 1))} '
             f'Firefox/3.6.{self.generator.random.randint(1, 20)}'),
            f'Gecko/{self.generator.date_time_between(datetime(2010, 1, 1))} Firefox/3.8',
        )
        tmplt_win = '({0}; {1}; rv:1.9.{2}.20) {3}'
        tmplt_lin = '({0}; rv:1.9.{1}.20) {2}'
        tmplt_mac = '({0}; rv:1.9.{1}.20) {2}'
        tmplt_and = '({0}; Mobile; rv:{1}.0) Gecko/{1}.0 Firefox/{1}.0'
        tmplt_ios = '({0}) AppleWebKit/{1} (KHTML, like Gecko) FxiOS/{2}.{3}.0 Mobile/{4} Safari/{1}'
        saf = '{}.{}'.format(self.generator.random.randint(531, 536),
                             self.generator.random.randint(0, 2))
        bld = self.lexify(self.numerify('##?###'), string.ascii_uppercase)
        bld2 = self.lexify(self.numerify('#?####'), string.ascii_lowercase)
        platforms = (
            tmplt_win.format(self.windows_platform_token(),
                             self.generator.locale().replace('_', '-'),
                             self.generator.random.randint(0, 2),
                             self.generator.random.choice(ver)),
            tmplt_lin.format(self.linux_platform_token(),
                             self.generator.random.randint(5, 7),
                             self.generator.random.choice(ver)),
            tmplt_mac.format(self.mac_platform_token(),
                             self.generator.random.randint(2, 6),
                             self.generator.random.choice(ver)),
            tmplt_and.format(self.android_platform_token(),
                             self.generator.random.randint(5, 68)),
            tmplt_ios.format(self.ios_platform_token(),
                             saf,
                             self.generator.random.randint(9, 18),
                             bld2,
                             bld),
        )

        return 'Mozilla/5.0 ' + self.random_element(platforms)

    def safari(self):
        """Generate a Safari web browser user agent string."""
        saf = (f'{self.generator.random.randint(531, 535)}.'
               f'{self.generator.random.randint(1, 50)}.'
               f'{self.generator.random.randint(1, 7)}')
        if not self.generator.random.getrandbits(1):
            ver = f'{self.generator.random.randint(4, 5)}.{self.generator.random.randint(0, 1)}'
        else:
            ver = f'{self.generator.random.randint(4, 5)}.0.{self.generator.random.randint(1, 5)}'
        tmplt_win = '(Windows; U; {0}) AppleWebKit/{1} (KHTML, like Gecko)' \
                    ' Version/{2} Safari/{3}'
        tmplt_mac = '({0} rv:{1}.0; {2}) AppleWebKit/{3} (KHTML, like Gecko)' \
                    ' Version/{4} Safari/{5}'
        tmplt_ipod = '(iPod; U; CPU iPhone OS {0}_{1} like Mac OS X; {2})' \
                     ' AppleWebKit/{3} (KHTML, like Gecko) Version/{4}.0.5' \
                     ' Mobile/8B{5} Safari/6{6}'
        locale = self.generator.locale().replace('_', '-')
        platforms = (
            tmplt_win.format(self.windows_platform_token(),
                             saf,
                             ver,
                             saf),
            tmplt_mac.format(self.mac_platform_token(),
                             self.generator.random.randint(2, 6),
                             locale,
                             saf,
                             ver,
                             saf),
            tmplt_ipod.format(self.generator.random.randint(3, 4),
                              self.generator.random.randint(0, 3),
                              locale,
                              saf,
                              self.generator.random.randint(3, 4),
                              self.generator.random.randint(111, 119),
                              saf),
        )

        return 'Mozilla/5.0 ' + self.random_element(platforms)

    def opera(self):
        """Generate an Opera web browser user agent string."""
        token = self.linux_platform_token() if self.generator.random.getrandbits(1) else self.windows_platform_token()
        locale = self.generator.locale().replace('_', '-')
        platform = (f'({token}; {locale}) Presto/2.9.{self.generator.random.randint(160, 190)} '
                    f'Version/{self.generator.random.randint(10, 12)}.00')
        return f'Opera/{self.generator.random.randint(8, 9)}.{self.generator.random.randint(10, 99)}.{platform}'

    def internet_explorer(self):
        """Generate an IE web browser user agent string."""
        return (f'Mozilla/5.0 (compatible; MSIE {self.generator.random.randint(5, 9)}.0; '
                f'{self.windows_platform_token()}; '
                f'Trident/{self.generator.random.randint(3, 5)}.{self.generator.random.randint(0, 1)})')

    def windows_platform_token(self):
        """Generate a Windows platform token used in user agent strings."""
        return self.random_element(self.windows_platform_tokens)

    def linux_platform_token(self):
        """Generate a Linux platform token used in user agent strings."""
        return f'X11; Linux {self.random_element(self.linux_processors)}'

    def mac_platform_token(self):
        """Generate a MacOS platform token used in user agent strings."""
        return (f'Macintosh; {self.random_element(self.mac_processors)} Mac OS X 10 '
                f'{self.generator.random.randint(5, 12)}_{self.generator.random.randint(0, 9)}')

    def android_platform_token(self):
        """Generate an Android platform token used in user agent strings."""
        return f'Android {self.random_element(self.android_versions)}'

    def ios_platform_token(self):
        """Generate an iOS platform token used in user agent strings."""
        apple_device = self.random_element(self.apple_devices)
        return (f'{apple_device}; CPU {apple_device} '
                f'OS {self.random_element(self.ios_versions).replace(".", "_")} like Mac OS X')
