"""Chrome Version History API calls"""

import re
import sys

import gam
from gam.var import *
from gam import controlflow
from gam import display
from gam import gapi
from gam import utils


def build():
    return gam.buildGAPIObjectNoAuthentication('versionhistory')


CHROME_HISTORY_ENTITY_CHOICES = {
  'platforms',
  'channels',
  'versions',
  'releases',
  }

CHROME_VERSIONHISTORY_ORDERBY_CHOICE_MAP = {
  'versions':  {
    'channel': 'channel',
    'name': 'name',
    'platform': 'platform',
    'version': 'version'
    },
  'releases': {
    'channel': 'channel',
    'endtime': 'endtime',
    'fraction': 'fraction',
    'name': 'name',
    'platform': 'platform',
    'starttime': 'starttime',
    'version': 'version'
    }
  }

CHROME_VERSIONHISTORY_TITLES = {
  'platforms': ['platform'],
  'channels':  ['channel', 'platform'],
  'versions': ['version', 'channel', 'platform',
               'major_version', 'minor_version', 'build', 'patch'],
  'releases': ['version', 'channel', 'platform',
               'major_version', 'minor_version', 'build', 'patch',
               'fraction', 'serving.startTime','serving.endTime']
  }

def get_relative_milestone(channel='stable', minus=0):
    '''
    takes a channel and minus like stable and -1.
    returns current given milestone number
    '''
    cv = build()
    parent = f'chrome/platforms/all/channels/{channel}/versions/all'
    releases = gapi.get_all_pages(cv.platforms().channels().versions().releases(),
                                  'list',
                                  'releases',
                                  parent=parent,
                                  fields='releases/version,nextPageToken')
    milestones = []
    # Note that milestones are usually sequential but some numbers
    # may be skipped. For example, there was no Chrome 82 stable.
    # Thus we need to do more than find the latest version and subtract.
    for release in releases:
        milestone = release.get('version').split('.')[0]
        if milestone not in milestones:
            milestones.append(milestone)
    milestones.sort(reverse=True)
    try:
        return milestones[minus]
    except IndexError:
        return ''

def get_platform_map(cv=None):
    '''returns dict mapping of platform choices'''
    if cv is None:
        cv = build()
    result = gapi.get_all_pages(cv.platforms(),
                                'list',
                                'platforms',
                                parent='chrome')
    platforms = [p.get('platformType', '').lower() for p in result]
    platform_map = {'all': 'all'}
    for cplatform in platforms:
        key = cplatform.replace('_', '')
        platform_map[key] = cplatform
    return platform_map


def get_channel_map(cv=None):
    '''returns dict mapping of channel choices'''
    if cv is None:
        cv = build()
    result = gapi.get_all_pages(cv.platforms().channels(),
                                'list',
                                'channels',
                                parent='chrome/platforms/all')
    channels = [c.get('channelType', '').lower() for c in result]
    channels = list(set(channels))
    channel_map = {'all': 'all'}
    for channel in channels:
        key = channel.replace('_', '')
        channel_map[key] = channel
    return channel_map

def printHistory():
    cv = build()
    entityType = sys.argv[3].lower().replace('_', '')
    if entityType not in CHROME_HISTORY_ENTITY_CHOICES:
        msg = f'{entityType} is not a valid argument to "gam print chromehistory"'
        controlflow.system_error_exit(3, msg)
    todrive = False
    csvRows = []
    cplatform = 'all'
    channel = 'all'
    version = 'all'
    kwargs = {}
    orderByList = []
    i = 4
    while i < len(sys.argv):
        myarg = sys.argv[i].lower().replace('_', '')
        if myarg == 'todrive':
            todrive = True
            i += 1
        elif entityType != 'platforms' and myarg == 'platform':
            cplatform = sys.argv[i + 1].lower().replace('_', '')
            platform_map = get_platform_map(cv)
            if cplatform not in platform_map:
                controlflow.expected_argument_exit('platform',
                                                   ', '.join(platform_map),
                                                   cplatform)
            cplatform = platform_map[cplatform]
            i += 2
        elif entityType in {'versions', 'releases'} and myarg == 'channel':
            channel = sys.argv[i + 1].lower().replace('_', '')
            channel_map = get_channel_map(cv)
            if channel not in channel_map:
                controlflow.expected_argument_exit('channel',
                                                   ', '.join(channel_map),
                                                   channel)
            channel = channel_map[channel]
            i += 2
        elif entityType == 'releases' and myarg == 'version':
            version = sys.argv[i + 1]
            i += 2
        elif entityType in {'versions', 'releases'} and myarg == 'orderby':
            fieldName = sys.argv[i + 1].lower().replace('_', '')
            i += 2
            if fieldName in CHROME_VERSIONHISTORY_ORDERBY_CHOICE_MAP[entityType]:
                fieldName = CHROME_VERSIONHISTORY_ORDERBY_CHOICE_MAP[entityType][fieldName]
                orderBy = ''
                if i < len(sys.argv):
                    orderBy = sys.argv[i].lower()
                    if orderBy in SORTORDER_CHOICES_MAP:
                        orderBy = SORTORDER_CHOICES_MAP[orderBy]
                        i += 1
                if orderBy != 'DESCENDING':
                    orderByList.append(fieldName)
                else:
                    orderByList.append(f'{fieldName} desc')
            else:
                controlflow.expected_argument_exit('orderby',
                                                   ', '.join(CHROME_VERSIONHISTORY_ORDERBY_CHOICE_MAP[entityType]),
                                                   fieldName)
        elif entityType in {'versions', 'releases'} and myarg == 'filter':
            kwargs['filter'] = sys.argv[i + 1]
            i += 2
        else:
            msg = f'{myarg} is not a valid argument to "gam print chromehistory {entityType}"'
            controlflow.system_error_exit(3, msg)
    if orderByList:
        kwargs['orderBy'] = ','.join(orderByList)
    if entityType == 'platforms':
        svc = cv.platforms()
        parent = 'chrome'
    elif entityType == 'channels':
        svc = cv.platforms().channels()
        parent = f'chrome/platforms/{cplatform}'
    elif entityType == 'versions':
        svc = cv.platforms().channels().versions()
        parent = f'chrome/platforms/{cplatform}/channels/{channel}'
    else: #elif entityType == 'releases'
        svc = cv.platforms().channels().versions().releases()
        parent = f'chrome/platforms/{cplatform}/channels/{channel}/versions/{version}'
    reportTitle = f'Chrome Version History {entityType.capitalize()}'
    page_message = gapi.got_total_items_msg(reportTitle, '...\n')
    gam.printGettingAllItems(reportTitle, None)
    citems = gapi.get_all_pages(svc, 'list', entityType,
                                page_message=page_message,
                                parent=parent,
                                fields=f'nextPageToken,{entityType}',
                                **kwargs)
    for citem in citems:
        for key in list(citem):
            if key.endswith('Type'):
                newkey = key[:-4]
                citem[newkey] = citem.pop(key)
        if 'channel' in citem:
            citem['channel'] = citem['channel'].lower()
        else:
            channel_match = re.search(r'\/channels\/([^/]*)', citem['name'])
            if channel_match:
                try:
                    citem['channel'] = channel_match.group(1)
                except IndexError:
                    pass
        if 'platform' in citem:
            citem['platform'] = citem['platform'].lower()
        else:
            platform_match = re.search(r'\/platforms\/([^/]*)', citem['name'])
            if platform_match:
                try:
                    citem['platform'] = platform_match.group(1)
                except IndexError:
                    pass

        if citem.get('version', '').count('.') == 3:
            citem['major_version'], \
            citem['minor_version'], \
            citem['build'], \
            citem['patch'] = citem['version'].split('.')
        citem.pop('name')
        csvRows.append(utils.flatten_json(citem))
    display.write_csv_file(csvRows, CHROME_VERSIONHISTORY_TITLES[entityType], reportTitle, todrive)
