#!/usr/bin/env python
# vim: ai ts=4 sts=4 et sw=4
#
# Copyright (C) 2017 Samsung Electronics, Co., Ltd.
#
#    This program is free software; you can redistribute it and/or
#    modify it under the terms of the GNU General Public License
#    as published by the Free Software Foundation; version 2
#    of the License.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#

import os
import sys
import re
from time import sleep
from datetime import datetime
import requests
import yaml
import ast
import copy
import base64
import json
from shutil import copyfile

from common.buildtrigger import trigger_next, trigger_info
from common.mapping import git_obs_map, git_obs_map_full_list
from common import utils
#from gbp.rpm import SpecFile
#from gbp.errors import GbpError
#from common.git import Git, clone_gitproject
from common.gerrit import GerritEnv, Gerrit

from common.workflow import get_info_from_tag

from common.workflow import MailSender

from common.utils import unicode_to_str

# set default char-set endcoding to utf-8
reload(sys)
sys.setdefaultencoding('utf-8') # pylint: disable-msg=E1101

HIGHLIGHT = '+'
GREYEDOUT = '-'

def request_sr_list_for_snapshot(project, snapshot, reason):

    ret_data = {'project': project, \
                'project_to_create': None, \
                'requests': []
               }
    # 'requests':
    #   [{
    #     'snapshot': 'snapshot-version-1',
    #     'submit_list': [
    #       {'sr-tag-name-1': ['git-path-11']},
    #       {'sr-tag-name-2': ['git-path-21','git-path-22']},
    #   }]

    # Request dashboard information
    if True:
        path = os.path.join(os.getenv('PUBLIC_DASHBOARD_API_URL'), \
                                         'snapshot.code?snapshot=%s' % snapshot)
        try:
            board_data = requests.get(os.path.join(os.getenv('PUBLIC_DASHBOARD_API_URL'), \
                               'snapshot.code?snapshot=%s' % snapshot)).text
        except Exception, err:
            os.system('wget %s -O myfile --no-check-certificate' % path)
            with open('myfile', 'r') as sf:
                board_data = sf.read()
        for line in board_data.replace('\\n', '').replace('\\', '').split('\n'):
            try:
                sr_list_from_snapshot = ast.literal_eval(line)
            except Exception, err:
                continue
        print sr_list_from_snapshot
        sr_list = []

        for sr in sr_list_from_snapshot:
            for index, item in enumerate(sr.get('packages')):
                sr_list.append({sr.get('sr'): [ {'repo': item.get('repo'),
                                                 'cid': item.get('cid'),
                                                 'snapshot': snapshot,
                                                 'submitter': sr.get('submitters')[index]}
                                              ]})
        ret_data['requests'].append({'snapshot': snapshot, 'submit_list': sr_list})
    return ret_data

def touch_trigger_data(raw_data):

    ret_data = {'project': raw_data.get('source'), \
                'project_to_create': None, \
                'requests': []
               }
    sr_list = []
    if True:
        checked_snapshots = []
        #TODO: Split requests into each snapshots
        for sr in raw_data.get('sr'):
            checked_snapshots.append(sr.get('snapshot'))
            for index, item in enumerate(sr.get('packages')):
                sr_list.append({sr.get('sr'): [ {'repo': item.get('repo'),
                                                 'cid': item.get('cid'),
                                                 'snapshot': sr.get('snapshot'),
                                                 'submitter': sr.get('submitters')[index].replace('\n', '')}
                                              ]})
        print checked_snapshots
        print sr_list
        ret_data['requests'].append({'snapshot': ','.join(list(set(checked_snapshots))), 'submit_list': sr_list})
    return ret_data

def main():
    """
    Script entry point.
    """

    print '---[JOB STARTED]-------------------------'

    #if os.getenv('SR_SYNC_ENABLED', '0') != '1':
    #    return

    bm_start_datetime = datetime.now()

    enabled_projects = ast.literal_eval(os.getenv('SR_SYNC_PROJECTS'))

    target_project = None
    reason = 'SR-SYNC'
    snapshot = None
    project_to_create_timestamp = None
    triggered_by = "tizen.build@samsung.com"

    if os.getenv('UPSTREAM_SNAPSHOT', None) and os.getenv('UPSTREAM_OBS_PROJECT', None):
        snapshot = os.getenv('UPSTREAM_SNAPSHOT')
        project = os.getenv('UPSTREAM_OBS_PROJECT')
        #target_project = os.getenv('TARGET_PROJECT')
        # Retrieve SR list of the snapshot from dashboard
        retry_count = 10
        while retry_count > 0:
            official_data = request_sr_list_for_snapshot(project, snapshot, reason)
            if len(official_data['requests'][0]['submit_list']) <= 0:
                print 'Fetching dashboard data failed, retrying...'
                retry_count -= 1; sleep(180); continue
            break
        if retry_count <= 0:
            raise Exception('Fail to fetch snapshot info from dashboard')
    elif os.getenv('TRIGGER_INFO', None):
        manual_trigger = trigger_info(os.getenv('TRIGGER_INFO'))
        project = manual_trigger.get('source')
        target_project = manual_trigger.get('target')
        project_to_create_timestamp = manual_trigger.get('project_to_create_timestamp')
        triggered_by = manual_trigger.get('useremail', triggered_by)
        # Parse triggered data
        official_data = touch_trigger_data(manual_trigger)
    else: # Consider file parameter comes
        with open('SUBMIT-REQUEST-SYNC.parm', 'r') as rf:
            file_raw = rf.readline()
            file_content = file_raw
        print file_content
        manual_trigger = unicode_to_str(json.loads(file_content).get('parameter'))
        project = manual_trigger.get('source')
        target_project = manual_trigger.get('target')
        project_to_create_timestamp = manual_trigger.get('project_to_create_timestamp')
        triggered_by = manual_trigger.get('useremail', triggered_by)
        # Parse triggered data
        official_data = touch_trigger_data(manual_trigger)

    for source_project in enabled_projects.keys():
        if source_project != project:
            del enabled_projects[source_project]
            continue
        enabled_projects[source_project] = \
                     [ x for x in enabled_projects[source_project] \
                       if (not target_project or x.get('target') == target_project) ]
    print 'enabled_projects: %s' % enabled_projects 
    if project not in enabled_projects:
        return
    if project_to_create_timestamp is None:
        project_to_create_timestamp = datetime.utcnow().strftime("%Y%m%d.%H%M%S")

    git_url = 'ssh://%s:%s' % (os.getenv('PUBLIC_GERRIT_HOSTNAME'),
                               os.getenv('PUBLIC_GERRIT_SSHPORT'))

    print '==== OFFICIAL_DATA ===='
    print 'project: %s' % official_data['project']
    print 'project_to_create: %s' % official_data['project_to_create']
    print 'requests:'
    for rq in official_data['requests']:
        print '  snapshot:%s' % rq['snapshot']
        if snapshot is None:
            snapshot = rq['snapshot']
        print '  submit_list:'
        for s in rq['submit_list']:
            print '    %s' % s.keys()[0]
            for g in s[s.keys()[0]]:
                print '      %s' % g

    for target in enabled_projects[project]:
        target_project = target['target']
        target_fork_prefix = target['fork']
        branch = target['branch']
        source_branch = target['source_branch']
        notify_domain = target['notify']
        if len(notify_domain) >= 0 and "@" in notify_domain[0]:
            triggered_by = notify_domain[0]

        if True:
            project_to_create = 'home:prerelease:%s:submit:%s:%s' \
                                % (target_project, \
                                   branch, \
                                   project_to_create_timestamp)

        ret_data = {'project': official_data['project'],
                    'project_to_create': project_to_create,
                    'requests': []}

        requests_item = {}
        requests_item[project_to_create] = []
        print '\n  >>>> Processing target %s\n  >>>> %s\n' % (target_project, project_to_create)

        # Remove forked git repo
        mapping = git_obs_map_full_list(target['target'])
        for rq in official_data['requests']:
            _conv = {'snapshot': rq['snapshot'], 'submit_list': []}
            for sr in rq['submit_list']:
                _sr_tag = sr.keys()[0]
                _sr_list = {_sr_tag: []}
                for item in sr[_sr_tag]:
                    repo = item.get('repo')
                    cid = item.get('cid')
                    smtr = item.get('submitter')
                    sn = item.get('snapshot')
                    bSetHighlight = True
                    bDeleted = False
                    for item in mapping:
                        # We only care about defined git repositories
                        if item.get('OBS_project', '') == target['target'] and \
                            item.get('Project_name', '') == target_fork_prefix + repo:
                            bSetHighlight = False
                        if item.get('OBS_project', '') == target['target'] and \
                            item.get('Project_name', '') == repo:
                            bSetHighlight = False
                            bDeleted = True
                    marked_repo = {'cid': cid, 'submitter': smtr, 'snapshot': sn, 'deleted': bDeleted}
                    if bSetHighlight:
                        marked_repo['repo'] = HIGHLIGHT + repo
                    else:
                        marked_repo['repo'] = GREYEDOUT + repo
                    if marked_repo not in _sr_list[_sr_tag]:
                        _sr_list[_sr_tag].append(marked_repo)
                if _sr_list[_sr_tag]:
                    _conv['submit_list'].append(_sr_list)
            if _conv['submit_list']:
                ret_data['requests'].append(_conv)
        print '\nret_data:\n%s\n' % ret_data

        myGerritEnv = GerritEnv('PUBLIC_')
        # Find OBS package name and trigger OBS project creation job
        for req in ret_data['requests']:
            print '  + Make requests: [%s]\n    %s\n' \
                  % (req['snapshot'], [ x.keys()[0] for x in req['submit_list'] ])
            for sr in req['submit_list']:
                for submit in sr.keys():
                    for item in sr[submit]:
                        git = item.get('repo')
                        cid = item.get('cid')
                        smtr = item.get('submitter')
                        sn = item.get('snapshot')
                        _package = ''
                        if True:#git.startswith(HIGHLIGHT):
                            if submit == 'submit':
                                _tag_info = get_info_from_tag(git[1:], source_branch, project, \
                                                              cid, myGerritEnv)
                            else:
                                _tag_info = get_info_from_tag(git[1:], source_branch, project, \
                                                              submit, myGerritEnv)
                            _package = _tag_info.get('spec_name', None)
                            _commit_id = _tag_info.get('commit_id', None)
                            if _package is None:
                                _package = os.path.basename(git)
                            if _package and _commit_id:
                                requests_item[project_to_create].append({'package': _package, \
                                                                         'git_tag': submit, \
                                                                         'cid': _commit_id, \
                                                                         'rev': cid, \
                                                                         'submitter': smtr, \
                                                                         'gerrit_project': git, \
                                                                         'deleted': item.get('deleted'), \
                                                                         'snapshot': sn})


        # Split request into smaller part
        split_step = 100
        for r in xrange(0, len(requests_item[project_to_create]), split_step):
            trigger_data = {'requests': [{project_to_create: requests_item[project_to_create][r:(r+split_step)]}], \
                            'obs_target_prj': project, \
                            'url': git_url, \
                            'obs_dest_prj': target['target'], \
                            'reason': reason, \
                            'snapshot': snapshot, \
                            'sync_user' : triggered_by, \
                            'index_sequence': '%d-%d' % ((r/split_step)+1, len(requests_item[project_to_create]))}

            if target.get('git-sync') == 'Yes':
                trigger_next('PRE_RELEASE_REQUEST_%s_%d' % (target['target'], (r/split_step)+1), \
                             trigger_data)
            if target.get('sr-sync') == 'Yes':
                trigger_next('SR_SYNC_PRE_RELEASE_REQUEST_%s_%d' % (target['target'], (r/split_step)+1), \
                             trigger_data)

                bm_end_datetime = datetime.now()
                bm_sync_git_tag = project_to_create.split(':'+target['target']+':')[-1].replace(':','/')
                bm_stage = "Sync_SR_Submit"
                bm_data = {"bm_stage" : bm_stage,
                           "commit_date" : str(bm_end_datetime),
                           "commit_msg" : "N/A",
                           "submit_date" : str(bm_end_datetime),
                           "submit_msg" : "N/A",
                           "submitter" : "<%s>" % triggered_by,
                           "bm_member_sr_info" : {project_to_create: requests_item[project_to_create][r:(r+split_step)]},
                           "bm_sync_git_tag" : bm_sync_git_tag,
                           "gerrit_project" : "N/A",
                           "gerrit_newrev" : "N/A",
                           "gerrit_account_name" : "tizen.build",
                           "bm_start_datetime": str(bm_start_datetime),
                           "bm_end_datetime": str(bm_end_datetime),
                           "bm_src_project_lst": [project_to_create],
                          }
                trigger_next("BUILD-MONITOR_%s_%s_%d" % (bm_stage, target['target'], r), bm_data)

        # Mail notification
        if False:
            mymail = MailSender()
            if len(snapshot.split(',')) > 1:
                mymail.add_title('[SR-Sync] %s(Manual) => %s' % (ret_data.get('project'), target_project))
            else:
                mymail.add_title('[SR-Sync] %s(%s) => %s' % (ret_data.get('project'), snapshot, target_project))
            mymail.add_message('Hello\n\nA virtual SR has been triggered for the below configuration;\n')
            mymail.add_message('Source:')
            mymail.add_message('  Project  : %s' % ret_data.get('project'))
            mymail.add_message('  Snapshots: %s' % snapshot)
            mymail.add_message('  Branch   : %s' % source_branch)
            mymail.add_message('Target')
            mymail.add_message('  Project  : %s' % target_project)
            mymail.add_message('  Branch   : %s' % branch)
            mymail.add_message('\nOBS Project: %s' % project_to_create)

            packages_to_be_synced = [ {'repo': x['gerrit_project'][1:],
                                       'package': x['package'],
                                       'tag': x['git_tag']}
                                      for x in requests_item[project_to_create]
                                      if x['gerrit_project'].startswith(HIGHLIGHT) ]
            packages_to_be_skipped = [ {'repo': x['gerrit_project'][1:],
                                        'package': x['package'],
                                        'tag': x['git_tag']}
                                       for x in requests_item[project_to_create]
                                       if x['gerrit_project'].startswith(GREYEDOUT) ]

            mymail.add_message('\nPACKAGES TO BE SYNCED (%d)' % len(packages_to_be_synced))
            mymail.add_message('====')
            for pt in packages_to_be_synced:
                mymail.add_message('%-15s: %s' % (pt['package'], pt['repo']))
            mymail.add_message('\nPACKAGES TO BE SKIPPED (%d)' % len(packages_to_be_skipped))
            mymail.add_message('====')
            for pt in packages_to_be_skipped:
                mymail.add_message('%s' % (pt['repo']))

            private_gerrit = Gerrit(os.getenv('GERRIT_HOSTNAME'),
                                    os.getenv('GERRIT_USERNAME'),
                                    os.getenv('GERRIT_SSHPORT'),
                                    int(os.getenv('GERRIT_SILENT_MODE')))

            # Add maintatiners to mail
            [mymail.add_maintainers(private_gerrit, group_name = name) for name in notify_domain]

            mymail.send_mail()
            del mymail

if __name__ == '__main__':
    sys.exit(main())

