# Copyright 2016 Pinterest, 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 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.

from django.middleware.csrf import get_token
from django.shortcuts import render, redirect
from django.template.loader import render_to_string
from django.http import HttpResponse
from django.contrib import messages
from django.views.generic import View

from deploy_board.settings import IS_PINTEREST
if IS_PINTEREST:
    from deploy_board.settings import DEFAULT_PROVIDER, DEFAULT_CMP_IMAGE, \
        DEFAULT_CMP_HOST_TYPE, DEFAULT_CMP_PINFO_ENVIRON, DEFAULT_CMP_ACCESS_ROLE, DEFAULT_CELL, \
        DEFAULT_PLACEMENT, USER_DATA_CONFIG_SETTINGS_WIKI, TELETRAAN_CLUSTER_READONLY_FIELDS
import json
import logging

from helpers import baseimages_helper, hosttypes_helper, securityzones_helper, placements_helper, \
    autoscaling_groups_helper, groups_helper, cells_helper
from helpers import clusters_helper, environs_helper, environ_hosts_helper
from helpers.exceptions import NotAuthorizedException, TeletraanException
import common
import traceback

log = logging.getLogger(__name__)

DEFAULT_PAGE_SIZE = 200


class EnvCapacityBasicCreateView(View):
    def get(self, request, name, stage):
        host_types = hosttypes_helper.get_by_provider(
            request, DEFAULT_PROVIDER)
        for host_type in host_types:
            host_type['mem'] = float(host_type['mem']) / 1024

        security_zones = securityzones_helper.get_by_provider_and_cell_name(
            request, DEFAULT_PROVIDER, DEFAULT_CELL)
        placements = placements_helper.get_by_provider_and_cell_name(
            request, DEFAULT_PROVIDER, DEFAULT_CELL)
        default_base_image = get_base_image_info_by_name(request, DEFAULT_CMP_IMAGE, DEFAULT_CELL)
        env = environs_helper.get_env_by_stage(request, name, stage)

        capacity_creation_info = {
            'environment': env,
            'hostTypes': host_types,
            'securityZones': security_zones,
            'placements': placements,
            'baseImages': default_base_image,
            'defaultCMPConfigs': get_default_cmp_configs(name, stage),
            'defaultProvider': DEFAULT_PROVIDER,
            'defaultHostType': DEFAULT_CMP_HOST_TYPE,
            'defaultSeurityZone': DEFAULT_PLACEMENT
        }
        # cluster manager
        return render(request, 'configs/new_capacity.html', {
            'env': env,
            'capacity_creation_info': json.dumps(capacity_creation_info)})

    def post(self, request, name, stage):
        log.info("Post to capacity with data {0}".format(request.body))
        try:
            cluster_name = '{}-{}'.format(name, stage)
            cluster_info = json.loads(request.body)

            log.info("Create Capacity in the provider")
            if 'configs' in cluster_info:
                for field in TELETRAAN_CLUSTER_READONLY_FIELDS:
                  if field in cluster_info['configs']:
                      log.error("Teletraan does not support user to change %s %s" % (field, cluster_info[field]))
                      raise TeletraanException("Teletraan does not support user to create %s" % s)

            clusters_helper.create_cluster_with_env(request, cluster_name, name, stage, cluster_info)

            log.info("Associate cluster_name to environment")
            # Update cluster info
            environs_helper.update_env_basic_config(
                request, name, stage, data={"clusterName": cluster_name})

            log.info("Update capacity to the environment")
            # set up env and group relationship
            environs_helper.add_env_capacity(
                request, name, stage, capacity_type="GROUP", data=cluster_name)
            return HttpResponse("{}", content_type="application/json")
        except NotAuthorizedException as e:
            log.error("Have an NotAuthorizedException error {}".format(e))
            return HttpResponse(e, status=403, content_type="application/json")
        except Exception as e:
            log.error("Have an error {}".format(e))
            return HttpResponse(e, status=500, content_type="application/json")


class EnvCapacityAdvCreateView(View):
    def get(self, request, name, stage):
        host_types = hosttypes_helper.get_by_provider(
            request, DEFAULT_PROVIDER)
        for host_type in host_types:
            host_type['mem'] = float(host_type['mem']) / 1024

        security_zones = securityzones_helper.get_by_provider_and_cell_name(
            request, DEFAULT_PROVIDER, DEFAULT_CELL)
        placements = placements_helper.get_by_provider_and_cell_name(
            request, DEFAULT_PROVIDER, DEFAULT_CELL)
        cells = cells_helper.get_by_provider(request, DEFAULT_PROVIDER)
        base_images = get_base_image_info_by_name(request, DEFAULT_CMP_IMAGE, DEFAULT_CELL)
        base_images_names = baseimages_helper.get_image_names(
            request, DEFAULT_PROVIDER, DEFAULT_CELL)

        env = environs_helper.get_env_by_stage(request, name, stage)
        provider_list = baseimages_helper.get_all_providers(request)

        capacity_creation_info = {
            'environment': env,
            'hostTypes': host_types,
            'securityZones': security_zones,
            'placements': placements,
            'cells': cells,
            'baseImages': base_images,
            'baseImageNames': base_images_names,
            'defaultBaseImage': DEFAULT_CMP_IMAGE,
            'defaultCMPConfigs': get_default_cmp_configs(name, stage),
            'defaultProvider': DEFAULT_PROVIDER,
            'defaultCell': DEFAULT_CELL,
            'defaultHostType': DEFAULT_CMP_HOST_TYPE,
            'defaultSeurityZone': DEFAULT_PLACEMENT,
            'providerList': provider_list,
            'configList': get_aws_config_name_list_by_image(DEFAULT_CMP_IMAGE)
        }
        # cluster manager
        return render(request, 'configs/new_capacity_adv.html', {
            'env': env,
            'capacity_creation_info': json.dumps(capacity_creation_info),
            'default_cmp_image': DEFAULT_CMP_IMAGE,
            'user_data_config_settings_wiki': USER_DATA_CONFIG_SETTINGS_WIKI,
            'is_pinterest': IS_PINTEREST})

    def post(self, request, name, stage):
        log.info("Post to capacity with data {0}".format(request.body))
        try:
            cluster_name = '{}-{}'.format(name, stage)
            cluster_info = json.loads(request.body)

            log.info("Create Capacity in the provider")
            clusters_helper.create_cluster(request, cluster_name, cluster_info)

            log.info("Update cluster_name to environment")
            # Update environment
            environs_helper.update_env_basic_config(request, name, stage,
                                                    data={"clusterName": cluster_name, "IsDocker": True})

            log.info("Update capacity to the environment")
            # set up env and group relationship
            environs_helper.add_env_capacity(
                request, name, stage, capacity_type="GROUP", data=cluster_name)

            return HttpResponse("{}", content_type="application/json")
        except NotAuthorizedException as e:
            log.error("Have an NotAuthorizedException error {}".format(e))
            return HttpResponse(e, status=403, content_type="application/json")
        except Exception as e:
            log.error("Have an error {}", e)
            return HttpResponse(e, status=500, content_type="application/json")


class ClusterConfigurationView(View):
    def get(self, request, name, stage):

        cluster_name = '{}-{}'.format(name, stage)
        current_cluster = clusters_helper.get_cluster(request, cluster_name)
        host_types = hosttypes_helper.get_by_provider(
            request, DEFAULT_PROVIDER)
        current_image = baseimages_helper.get_by_id(
            request, current_cluster['baseImageId'])
        current_cluster['baseImageName'] = current_image['abstract_name']
        for host_type in host_types:
            host_type['mem'] = float(host_type['mem']) / 1024

        cells = cells_helper.get_by_provider(request, current_cluster['provider'])
        security_zones = securityzones_helper.get_by_provider_and_cell_name(
            request, current_cluster['provider'], current_cluster['cellName'])
        placements = placements_helper.get_by_provider_and_cell_name(
            request, current_cluster['provider'], current_cluster['cellName'])
        base_images = get_base_image_info_by_name(
            request, current_image['abstract_name'], current_cluster['cellName'])
        base_images_names = baseimages_helper.get_image_names(
            request, current_cluster['provider'], current_cluster['cellName'])

        env = environs_helper.get_env_by_stage(request, name, stage)
        provider_list = baseimages_helper.get_all_providers(request)

        capacity_creation_info = {
            'environment': env,
            'cells': cells,
            'hostTypes': host_types,
            'securityZones': security_zones,
            'placements': placements,
            'baseImages': base_images,
            'baseImageNames': base_images_names,
            'defaultBaseImage': DEFAULT_CMP_IMAGE,
            'defaultCMPConfigs': get_default_cmp_configs(name, stage),
            'defaultProvider': DEFAULT_PROVIDER,
            'providerList': provider_list,
            'readonlyFields': TELETRAAN_CLUSTER_READONLY_FIELDS,
            'configList': get_aws_config_name_list_by_image(DEFAULT_CMP_IMAGE),
            'currentCluster': current_cluster
        }

        return render(request, 'clusters/cluster_configuration.html', {
            'env': env,
            'capacity_creation_info': json.dumps(capacity_creation_info),
            'default_cmp_image': DEFAULT_CMP_IMAGE,
            'user_data_config_settings_wiki': USER_DATA_CONFIG_SETTINGS_WIKI,
            'is_pinterest': IS_PINTEREST})

    def post(self, request, name, stage):
        try:
            env = environs_helper.get_env_by_stage(request, name, stage)
            cluster_name = env.get('clusterName')
            cluster_info = json.loads(request.body)
            log.info("Update Cluster Configuration with {}", cluster_info)

            cluster_name = '{}-{}'.format(name, stage)
            current_cluster = clusters_helper.get_cluster(request, cluster_name)
            log.info("getting current Cluster Configuration is {}", current_cluster)
            if 'configs' in current_cluster and 'configs' in cluster_info:
                for field in TELETRAAN_CLUSTER_READONLY_FIELDS:
                    if field in current_cluster['configs'] and field in cluster_info['configs']:
                        if current_cluster['configs'][field] != cluster_info['configs'][field]:
                            log.error("Teletraan does not support user to update %s %s" % (field, cluster_info['spiffe_id']))
                            raise TeletraanException("Teletraan does not support user to update %s" % field)

                    if field in current_cluster['configs'] and field not in cluster_info['configs']:
                        log.error("Teletraan does not support user to remove %s %s" % (field, cluster_info[field]))
                        raise TeletraanException("Teletraan does not support user to remove %s" % field)

            image = baseimages_helper.get_by_id(request, cluster_info['baseImageId'])
            clusters_helper.update_cluster(request, cluster_name, cluster_info)
        except NotAuthorizedException as e:
            log.error("Have an NotAuthorizedException error {}".format(e))
            return HttpResponse(e, status=403, content_type="application/json")
        except Exception as e:
            log.error("Post to cluster configuration view has an error {}", e)
            return HttpResponse(e, status=500, content_type="application/json")
        return HttpResponse(json.dumps(cluster_info), content_type="application/json")


class ClusterCapacityUpdateView(View):
    def post(self, request, name, stage):
        log.info("Update Cluster Capacity with data {}".format(request.body))
        try:
            settings = json.loads(request.body)
            cluster_name = '{}-{}'.format(name, stage)
            log.info("Update cluster {0} with {1}".format(
                cluster_name, settings))
            minSize = int(settings['minsize'])
            maxSize = int(settings['maxsize'])
            clusters_helper.update_cluster_capacity(
                request, cluster_name, minSize, maxSize)
        except NotAuthorizedException as e:
            log.error("Have an NotAuthorizedException error {}".format(e))
            return HttpResponse(e, status=403, content_type="application/json")
        except Exception as e:
            log.error("Post to cluster capacity view has an error {}", e)
            return HttpResponse(e, status=500, content_type="application/json")
        return HttpResponse(json.dumps(settings), content_type="application/json")


def create_base_image(request):
    params = request.POST
    base_image_info = {}
    base_image_info['abstract_name'] = params['abstractName']
    base_image_info['provider_name'] = params['providerName']
    base_image_info['provider'] = params['provider']
    base_image_info['description'] = params['description']
    base_image_info['cell_name'] = params['cellName']
    if 'basic' in params:
        base_image_info['basic'] = True
    else:
        base_image_info['basic'] = False
    baseimages_helper.create_base_image(request, base_image_info)
    return redirect('/clouds/baseimages')


def get_base_images(request):
    index = int(request.GET.get('page_index', '1'))
    size = int(request.GET.get('page_size', DEFAULT_PAGE_SIZE))
    base_images = baseimages_helper.get_all(request, index, size)
    provider_list = baseimages_helper.get_all_providers(request)
    cells_list = cells_helper.get_by_provider(request, DEFAULT_PROVIDER)

    return render(request, 'clusters/base_images.html', {
        'base_images': base_images,
        'provider_list': provider_list,
        'cells_list': cells_list,
        'pageIndex': index,
        'pageSize': DEFAULT_PAGE_SIZE,
        'disablePrevious': index <= 1,
        'disableNext': len(base_images) < DEFAULT_PAGE_SIZE,
    })


def get_image_names_by_provider_and_cell(request, provider, cell):
    image_names = baseimages_helper.get_image_names(request, provider, cell)
    return HttpResponse(json.dumps(image_names), content_type="application/json")


def get_images_by_provider_and_cell(request, provider, cell):
    images = baseimages_helper.get_all_by(request, provider, cell)
    return HttpResponse(json.dumps(images), content_type="application/json")


def get_placements_by_provider_and_cell(request, provider, cell):
    data = placements_helper.get_by_provider_and_cell_name(request, provider, cell)
    return HttpResponse(json.dumps(data), content_type="application/json")


def get_security_zones_by_provider_and_cell(request, provider, cell):
    data = securityzones_helper.get_by_provider_and_cell_name(request, provider, cell)
    return HttpResponse(json.dumps(data), content_type="application/json")


def get_image_names(request):
    params = request.GET
    provider = params['provider']
    env_name = params['env']
    stage_name = params['stage']
    cell = params.get('cell', DEFAULT_CELL)
    image_names = baseimages_helper.get_image_names(request, provider, cell)
    curr_image_name = None
    curr_base_image = None
    if 'curr_base_image' in params:
        curr_base_image = params['curr_base_image']
        image = baseimages_helper.get_by_id(request, curr_base_image)
        curr_image_name = image.get('abstract_name')

    contents = render_to_string("clusters/get_image_name.tmpl", {
        'image_names': image_names,
        'curr_image_name': curr_image_name,
        'curr_base_image': curr_base_image,
        'provider': provider,
        'env_name': env_name,
        'stage_name': stage_name,
    })
    return HttpResponse(json.dumps(contents), content_type="application/json")


def get_base_images_by_name(request):
    params = request.GET
    cell = params.get('cell', DEFAULT_CELL)
    base_images = None
    if 'name' in params:
        name = params['name']
        base_images = baseimages_helper.get_by_name(request, name, cell)

    curr_base_image = None
    if 'curr_base_image' in params:
        curr_base_image = params['curr_base_image']
        image = baseimages_helper.get_by_id(request, curr_base_image)
        curr_image_name = image.get('abstract_name')
        base_images = baseimages_helper.get_by_name(request, curr_image_name, cell)

    contents = render_to_string("clusters/get_base_image.tmpl", {
        'base_images': base_images,
        'curr_base_image': curr_base_image,
    })
    return HttpResponse(json.dumps(contents), content_type="application/json")


def get_base_image_info_by_name(request, name, cell):
    if name.startswith('cmp_base'):
        base_images = baseimages_helper.get_acceptance_by_name(request, name, cell)
        with_acceptance_rs = []
        if base_images:
            for image in base_images:
                r = image.get('baseImage')
                if r:
                    r['acceptance'] = image.get('acceptance', 'UNKNOWN')
                    with_acceptance_rs.append(r)
        return with_acceptance_rs
    return baseimages_helper.get_by_name(request, name, cell)


def get_base_images_by_name_json(request, name):
    cell = DEFAULT_CELL
    params = request.GET
    if params:
        cell = params.get('cell', DEFAULT_CELL)
    base_images = get_base_image_info_by_name(request, name, cell)
    return HttpResponse(json.dumps(base_images), content_type="application/json")


def create_host_type(request):
    params = request.POST
    host_type_info = {}
    host_type_info['abstract_name'] = params['abstractName']
    host_type_info['provider_name'] = params['providerName']
    host_type_info['provider'] = params['provider']
    host_type_info['description'] = params['description']
    host_type_info['mem'] = float(params['mem']) * 1024
    host_type_info['core'] = int(params['core'])
    host_type_info['storage'] = params['storage']
    if 'basic' in params:
        host_type_info['basic'] = True
    else:
        host_type_info['basic'] = False
    hosttypes_helper.create_host_type(request, host_type_info)
    return redirect('/clouds/hosttypes')


def get_host_types(request):
    index = int(request.GET.get('page_index', '1'))
    size = int(request.GET.get('page_size', DEFAULT_PAGE_SIZE))
    host_types = hosttypes_helper.get_all(request, index, size)
    for host_type in host_types:
        host_type['mem'] = float(host_type['mem']) / 1024
    provider_list = baseimages_helper.get_all_providers(request)

    return render(request, 'clusters/host_types.html', {
        'host_types': host_types,
        'provider_list': provider_list,
        'pageIndex': index,
        'pageSize': DEFAULT_PAGE_SIZE,
        'disablePrevious': index <= 1,
        'disableNext': len(host_types) < DEFAULT_PAGE_SIZE,
    })


def get_host_types_by_provider(request):
    params = request.GET
    provider = params['provider']
    curr_host_type = None
    if 'curr_host_type' in params:
        curr_host_type = params['curr_host_type']

    host_types = hosttypes_helper.get_by_provider(request, provider)
    for host_type in host_types:
        host_type['mem'] = float(host_type['mem']) / 1024

    contents = render_to_string("clusters/get_host_type.tmpl", {
        'host_types': host_types,
        'curr_host_type': curr_host_type,
    })
    return HttpResponse(json.dumps(contents), content_type="application/json")


def get_host_type_info(request):
    index = int(request.GET.get('page_index', '1'))
    size = int(request.GET.get('page_size', DEFAULT_PAGE_SIZE))
    host_types = hosttypes_helper.get_all(request, index, size)
    for host_type in host_types:
        host_type['mem'] = float(host_type['mem']) / 1024
    return HttpResponse(json.dumps(host_types), content_type="application/json")


def create_security_zone(request):
    params = request.POST
    security_zone_info = {}
    security_zone_info['abstract_name'] = params['abstractName']
    security_zone_info['provider_name'] = params['providerName']
    security_zone_info['provider'] = params['provider']
    security_zone_info['description'] = params['description']
    security_zone_info['cell_name'] = params.get('cellName', DEFAULT_CELL)
    if 'basic' in params:
        security_zone_info['basic'] = True
    else:
        security_zone_info['basic'] = False
    securityzones_helper.create_security_zone(request, security_zone_info)
    return redirect('/clouds/securityzones')


def get_security_zones(request):
    index = int(request.GET.get('page_index', '1'))
    size = int(request.GET.get('page_size', DEFAULT_PAGE_SIZE))