#!python
# Copyright 2019-2022 DADoES, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License in the root directory in the "LICENSE" file or at:
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import sys
from distutils import util
import anatools
from anatools.lib.channel import Channel, find_channelfile

LATESTANAVERSION = 1

parser = argparse.ArgumentParser()
parser.add_argument('--channel', default=None)
parser.add_argument('--channelId', default=None)
parser.add_argument('--environment', default='prod')
parser.add_argument('--email', default=None)
parser.add_argument('--password', default=None)
parser.add_argument('--local', type=util.strtobool, default=False)
parser.add_argument('--verbose', default=False)
parser.add_argument('--enforce_size_limit', type=util.strtobool, default=True)
args = parser.parse_args()
if args.verbose: verbose = 'debug'
else: verbose = False

if not args.enforce_size_limit:
    print('\033[93m' + 'WARNING: You have turned off the Docker build size limit, so you may face issues deploying channels larger than 7.5GB.' + '\033[0m')

def check_organization_volumes(organizationId, volumes):
    if len(volumes) > 0:
        # Check for volumes that user's organization(s) can't access
        orgVolumes = client.get_volumes(organizationId=organizationId)
        if orgVolumes: volumes_accessed = [v['volumeId'] for v in orgVolumes]
        else: volumes_accessed = []
        missing_volumes=[]
        for vol_id in volumes:
            if vol_id not in volumes_accessed:
                missing_volumes.append(vol_id)
                
        if len(missing_volumes) > 0:
            print("Your organization does not have access to a volume required by the channel. Re-check volume ID's in package.yml file or contact your administrator for access.")
            print("Volume(s) missing access:")
            print('\n'.join(missing_volumes))
            print('Exiting...'); sys.exit(0)

def check_channel_name(channelname, list_to_check):
    name = channelname
    channel_check_string = f", default is {channelname}"
    while True:
        if name in list_to_check: channel_check_string = f", '{name}' is taken"
        name = input(f"Please provide a name for the channel{channel_check_string}: ")
        if not name: name = channelname
        print(f"You provided name: {name}")
        if name not in list_to_check:
            break
    return name

# find the channel file
if args.channel is None: args.channel = find_channelfile()
if args.channel is None: print('No channel file was specified or found.'); sys.exit(1)

# determine channel volumes
volumes = []
channel = Channel(args.channel)
for package in channel.packages.keys():
    if channel.packages[package] is None:
        continue
    if 'volumes' in channel.packages[package]:
        for volume in channel.packages[package]['volumes'].keys():
            if volume != 'local':
                volumes.append(channel.packages[package]['volumes'][volume])

# build and deploy the channel
client = anatools.client(
    environment=args.environment, 
    email=args.email, 
    password=args.password,
    interactive=False,
    local=args.local,
    verbose=verbose)
if len(client.organizations) == 0: sys.exit(1)
channels = []
organizations = client.get_organizations()

organizations = [organization for organization in organizations if organization['role'] != 'guest']
for organization in organizations:
    managedChannels = client.get_managed_channels(organizationId=organization['organizationId'])
    for channel in managedChannels:
        channels.append({
            'organizationId': organization['organizationId'],
            'organizationName': organization['name'],
            'channelId': channel['channelId'],
            'channelName': channel['name'] })

if args.channelId is None:
    print("Please select one of the following options:")
    print(f"\t{'[0]'.ljust(5)} Create a new managed channel.")
    val = 1
    for channel in channels:
        print(f"\t{f'[{val}]'.ljust(5)} Deploy to {channel['channelName']} channel in the {channel['organizationName']} organization.")
        val += 1
    resp = input('Enter your choice: ')
    try:
        resp = int(resp)
        if resp not in range(val): raise Exception()
    except: print('Invalid choice, exiting...'); sys.exit(0)
    if resp == 0:
        print("Select an organization to create a new managed channel in:")
        val = 0
        for organization in organizations:
            print(f"\t{f'[{val}]'.ljust(5)} {organization['name']}")
            val += 1
        resp = input('Enter your choice: ')
        try:
            resp = int(resp)
            if resp not in range(val): raise Exception()
        except: print('Invalid choice, exiting...'); sys.exit(0)
        check_organization_volumes(organizations[resp]['organizationId'], volumes)
        resp2 = input(f"Creating a new channel using the {args.channel} channel file in {organizations[resp]['name']} organization. Continue (y/n)? ")
        if resp2.lower() == 'y':
            channelname = args.channel.split('/')[-1].split('.')[0]
            list_to_check = [channel['channelName'] for channel in channels if channel['organizationId'] == organizations[resp]['organizationId']]
            name = check_channel_name(channelname, list_to_check)
            channelId = client.create_managed_channel(name=name, volumes=volumes, organizationId=organizations[resp]['organizationId'])
            if channelId: 
                    deploymentId = client.deploy_managed_channel(channelId=channelId, channelfile=args.channel, enforce_size_limit=args.enforce_size_limit)
                    if deploymentId: client.get_deployment_status(deploymentId, stream=True)

        else: print('Exiting...'); sys.exit(0)

    else:
        check_organization_volumes(channels[resp-1]['organizationId'], volumes)
        resp2 = input(f"Deploying {args.channel} channel to {channels[resp-1]['channelName']} channel in {channels[resp-1]['organizationName']} organization. Continue (y/n)? ")
        if resp2.lower() == 'y':
            managedChannel = client.get_managed_channels(channelId=channels[resp-1]['channelId'])
            if managedChannel[0]['interfaceVersion'] != LATESTANAVERSION:
                resp3 = input(f"The {channels[resp-1]['channelName']} channel in {channels[resp-1]['organizationName']} organization uses the Ana Interface version {managedChannel[0]['interfaceVersion']}. Do you wish to upgrade (y/n)? ")
                if resp3.lower() == 'y':
                    client.edit_managed_channel(channelId=channels[resp-1]['channelId'], interfaceVersion=LATESTANAVERSION)
            if managedChannel[0]['volumes'] != volumes:
                resp3 = input(f"The {channels[resp-1]['channelName']} channel in {channels[resp-1]['organizationName']} organization has different volumes than your local channel. Do you wish to update the volumes (y/n)? ")
                if resp3.lower() == 'y':
                    client.edit_managed_channel(channelId=channels[resp-1]['channelId'], volumes=volumes)
            deploymentId = client.deploy_managed_channel(channelId=channels[resp-1]['channelId'], channelfile=args.channel, enforce_size_limit=args.enforce_size_limit)
            if deploymentId:
                client.get_deployment_status(deploymentId, stream=True) 
        else: print('Exiting...'); sys.exit(0)
        
else:
    selectedchannels = [channel for channel in channels if channel['channelId'] == args.channelId]
    if len(selectedchannels):
        check_organization_volumes(selectedchannels[0]['organizationId'], volumes)
        resp2 = input(f"Deploying {args.channel} channel to {selectedchannels[0]['channelName']} channel in {selectedchannels[0]['organizationName']} organization. Continue (y/n)? ")
        if resp2.lower() == 'y':
            managedChannel = client.get_managed_channels(channelId=args.channelId)
            if managedChannel[0]['interfaceVersion'] != LATESTANAVERSION:
                resp3 = input(f"The {selectedchannels[0]['channelName']} channel in {selectedchannels[0]['organizationName']} organization uses the Ana Interface version {managedChannel[0]['interfaceVersion']}. Do you wish to upgrade (y/n)? ")
                if resp3.lower() == 'y':
                    client.edit_managed_channel(channelId=args.channelId, interfaceVersion=LATESTANAVERSION)
            if managedChannel[0]['volumes'] != volumes:
                resp3 = input(f"The {selectedchannels[0]['channelName']} channel in {selectedchannels[0]['organizationName']} organization has different volumes than your local channel. Do you wish to update the volumes (y/n)? ")
                if resp3.lower() == 'y':
                    client.edit_managed_channel(channelId=args.channelId, volumes=volumes)
            deploymentId = client.deploy_managed_channel(channelId=args.channelId, channelfile=args.channel, enforce_size_limit=args.enforce_size_limit)
            if deploymentId:
                client.get_deployment_status(deploymentId, stream=True)
    else: print(f'Could not find a channel with channelId {args.channelId} in your managed channels. Exiting..;')


