#!/usr/bin/env python

import time

# Copyright 2017 Nitor Creations Oy
#
# 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 builtins import str

from threadlocal_aws.clients import cloudfront, route53
from n_utils.route53_util import hosted_zones, longest_matching_zone


def distributions():
    pages = cloudfront().get_paginator("list_distributions")
    print(pages.paginate())
    for page in pages.paginate():
        print(page)
        distribution_list = page.get("DistributionList")
        for distribution in distribution_list["Items"]:
            yield distribution["Id"]


def distribution_comments():
    pages = cloudfront().get_paginator("list_distributions")
    for page in pages.paginate():
        distribution_list = page.get("DistributionList")
        for distribution in distribution_list["Items"]:
            yield distribution["Comment"]


def get_distribution_by_id(distribution_id):
    ret = cloudfront().get_distribution(Id=distribution_id)["Distribution"]
    ret["DistributionConfig"]["Id"] = distribution_id
    ret["DistributionConfig"]["DomainName"] = ret["DomainName"]
    return [ret["DistributionConfig"]]


def get_distribution_by_comment(comment):
    pages = cloudfront().get_paginator("list_distributions")
    ret = []
    for page in pages.paginate():
        distribution_list = page.get("DistributionList")
        for distribution in distribution_list["Items"]:
            if comment == distribution["Comment"]:
                ret.append(distribution)
    if not ret:
        raise Exception("Failed to find distribution with comment " + comment)
    else:
        return ret


def upsert_cloudfront_records(args):
    distributions = None
    if args.distribution_id:
        distributions = get_distribution_by_id(args.distribution_id)
    else:
        distributions = get_distribution_by_comment(args.distribution_comment)
    zones = list(hosted_zones())
    changes = {}
    for distribution in distributions:
        if "Aliases" in distribution:
            print(
                "Upserting records for "
                + distribution["Id"]
                + " ("
                + distribution["Comment"]
                + ")"
            )
            for alias in distribution["Aliases"]["Items"]:
                change = get_record_change(
                    alias, distribution["DomainName"], distribution["Id"], zones
                )
                if not change["HostedZoneId"] in changes:
                    changes[change["HostedZoneId"]] = []
                changes[change["HostedZoneId"]].append(change["Change"])
    requests = []
    for req in list(changes.keys()):
        requests.append(
            route53().change_resource_record_sets(
                HostedZoneId=req, ChangeBatch={"Changes": changes[req]}
            )["ChangeInfo"]
        )
    if args.wait:
        not_synced_count = 1
        while not_synced_count > 0:
            not_synced_count = 0
            for req in requests:
                if (
                    not route53().get_change(Id=req["Id"])["ChangeInfo"]["Status"]
                    == "INSYNC"
                ):
                    not_synced_count = not_synced_count + 1
            if not_synced_count > 0:
                print(
                    "Waiting for requests to sync - "
                    + str(not_synced_count)
                    + " not synced"
                )
                time.sleep(2)
            else:
                print(str(len(requests)) + " requests INSYNC")


def get_record_change(alias, dns_name, distribution_id, hosted_zones):
    zone = longest_matching_zone(alias, hosted_zones)
    if zone:
        print(
            alias + " => " + dns_name + "(" + distribution_id + ") in " + zone["Name"]
        )
        if alias + "." == zone["Name"]:
            type = "A"
        else:
            type = "CNAME"
        change = {
            "Action": "UPSERT",
            "ResourceRecordSet": {"Name": alias, "Type": type},
        }
        if type == "A":
            change["ResourceRecordSet"]["AliasTarget"] = {
                "HostedZoneId": "Z2FDTNDATAQYW2",
                "DNSName": dns_name,
                "EvaluateTargetHealth": False,
            }
        else:
            change["ResourceRecordSet"]["ResourceRecords"] = [{"Value": dns_name}]
            change["ResourceRecordSet"]["TTL"] = 300

        return {"HostedZoneId": zone["Id"], "Change": change}
