#!python
"""LICENSE
Copyright 2017 Hermann Krumrey <hermann@krumreyh.com>

This file is part of ci-scripts.

ci-scripts 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, either version 3 of the License, or
(at your option) any later version.

ci-scripts 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 ci-scripts.  If not, see <http://www.gnu.org/licenses/>.
LICENSE"""

import os
import sys
# noinspection PyPackageRequirements
import httplib2
# noinspection PyPackageRequirements
from oauth2client import client
# noinspection PyUnresolvedReferences,PyPackageRequirements
from apiclient.discovery import build as build_google_service
# noinspection PyPackageRequirements
from oauth2client.service_account import ServiceAccountCredentials
from ci_scripts.common import process_call, decode_base64_string_to_file


def main():
    """
    The main method of the script. Parses the arguments and then attempts to
    upload the release to the Google Play Store
    :return: None
    """

    package = sys.argv[1]
    track = sys.argv[2]
    email = os.environ["PLAY_UPLOAD_EMAIL"]
    keyfile = "key.p12"

    changes = prepare_changelogs()
    decode_base64_string_to_file(os.environ["PLAY_UPLOAD_SECRET"], keyfile)
    apks = "artifacts/*.apk"

    try:
        service_info = build_service(email, keyfile, package)
        version_code = upload_apks(service_info, apks)
        set_apk_track_info(service_info, track, version_code)
        upload_release_notes(service_info, version_code, ",".join(changes))

        commit_request = service_info["service"].edits().commit(
            editId=service_info["edit_id"], packageName=package).execute()

        print("Edit " + commit_request['id'] + " has been committed")

    except client.AccessTokenRefreshError:
        print("Authentication Failed")
        sys.exit(1)


def prepare_changelogs():
    """
    Prepares the changelogs to upload.
    :return: A list of changelog files named after their respective languages
    """

    changelog_files = list(filter(
        lambda x: x.startswith("CHANGELOG"),
        os.listdir(".")
    ))
    changelogs = []
    for changelog in changelog_files:
        if "-" in changelog:
            lang = changelog.split("-", 1)[1]
        else:
            lang = "en-US"
        process_call(["changelog-reader", "-c", changelog, "-o", lang])
        changelogs.append(lang)
    return changelogs


def build_service(email, keyfile, package_name):
    """
    Builds the Google API service used for all further API interactions
    :param email: The API Service Account email address
    :param keyfile: The p12 keyfile location
    :param package_name: The name of the package to upload to
    :return: The Service, the edit request ID and the package name
             as a dictionary for convenient further use
    """

    credentials = ServiceAccountCredentials.from_p12_keyfile(
        email, keyfile,
        scopes="https://www.googleapis.com/auth/androidpublisher"
    )

    http = httplib2.Http()
    http = credentials.authorize(http)
    service = build_google_service("androidpublisher", "v2", http=http)

    edit_request = service.edits().insert(body={}, packageName=package_name)
    return {"service": service,
            "edit_id": edit_request.execute()["id"],
            "package": package_name}


def upload_apks(service_info, apks):
    """
    Uploads any APK files provided via the command line arguments
    :param service_info: The previously established service info dictionary
    :param apks: The APK files to upload
    :return: The uploaded version code for the APK
    """
    apk_response = service_info["service"].edits().apks().upload(
        editId=service_info["edit_id"],
        packageName=service_info["package"],
        media_body=apks).execute()

    version_code = apk_response['versionCode']
    print("Uploaded APK for version " + str(version_code))
    return version_code


def set_apk_track_info(service_info, track, version_code):
    """
    Sets the specified track to include the specified version
    :param service_info: The previously generated API service dictionary
    :param track: The track to apply these changes to
    :param version_code: The version code to add to the track
    :return: None
    """
    service_info["service"].edits().tracks().update(
        editId=service_info["edit_id"],
        track=track,
        packageName=service_info["package"],
        body={"versionCodes": [version_code]}).execute()

    print("Version " + str(version_code) + " has been assigned "
                                           "to track " + track + ".")


def upload_release_notes(service_info, version_code, change_notes):
    """
    Uploads release notes for various languages
    :param service_info: The service dictionary
    :param version_code: The version code of the APK
    :param change_notes: The release notes to upload, stored in files,
                         whose paths are provided in a comma-separated string.
                         The language is determined by the name of the file
    :return: None
    """

    for notes in change_notes.rstrip().lstrip().split(","):

        language = os.path.basename(notes)
        with open(notes, 'r') as notes_file:
            changes = notes_file.read()

        service_info["service"].edits().apklistings().update(
            editId=service_info["edit_id"],
            packageName=service_info["package"],
            language=language,
            apkVersionCode=version_code,
            body={'recentChanges': changes}).execute()

        print("Release Notes for language " + language + " were updated.")


if __name__ == "__main__":
    main()
