import datetime
from typing import Any

from app.extensions import db
from app.models.mirrors import Proxy
from app.terraform.proxy import ProxyAutomation, update_smart_proxy_instance


class ProxyCloudfrontAutomation(ProxyAutomation):
    short_name = "proxy_cloudfront"
    description = "Deploy proxies to AWS CloudFront"
    provider = "cloudfront"
    smart_proxies = True
    cloud_name = "aws"

    template_parameters = [
        "admin_email",
        "aws_access_key",
        "aws_secret_key",
        "smart_zone"
    ]

    template = """
    terraform {
      {{ backend_config }}
      required_providers {
        acme = {
          source = "vancluever/acme"
          version = "~> 2.11.0"
        }
        aws = {
          version = "~> 4.41.0"
        }
      }
    }

    provider "acme" {
      server_url = "https://acme-v02.api.letsencrypt.org/directory"
    }

    provider "aws" {
      access_key = "{{ aws_access_key }}"
      secret_key = "{{ aws_secret_key }}"
      region = "us-east-2"
    }

    locals {
      smart_zone = "{{ smart_zone }}"
    }

    {% for group in groups %}
    module "label_{{ group.id }}" {
      source  = "cloudposse/label/null"
      version = "0.25.0"
      namespace = "{{ global_namespace }}"
      tenant = "{{ group.group_name }}"
      label_order = ["namespace", "tenant", "name", "attributes"]
    }

    module "log_bucket_{{ group.id }}" {
      source = "cloudposse/s3-log-storage/aws"
      version = "0.28.0"
      context = module.label_{{ group.id }}.context
      name = "logs"
      attributes = ["cloudfront"]
      acl                      = "log-delivery-write"
      standard_transition_days = 30
      glacier_transition_days  = 60
      expiration_days          = 90
    }

    resource "aws_sns_topic" "alarms_{{ group.id }}" {
      name = "${module.label_{{ group.id }}.id}-cloudfront-alarms"
    }

    {% for origin in group.origins | selectattr("destroyed", "none") | selectattr("smart") %}
    {% if loop.first %}
    module "smart_proxy_{{ group.id }}" {
      source  = "{{ terraform_modules_path }}/terraform-aws-bc-smart-proxy-instance"
      context = module.label_{{ group.id }}.context
      name = "smart-proxy"
      config_filename = "smart_proxy.{{ group.id }}.conf"
      disable_api_termination = false
      dns_zone = "{{ smart_zone }}"
      letsencrypt_email_address = "{{ admin_email }}"
      max_transfer_per_hour = "13000000000"
    }
    {% endif %}
    {% endfor %}
    {% endfor %}

    {% for proxy in proxies %}
    module "cloudfront_{{ proxy.id }}" {
      source = "{{ terraform_modules_path }}/terraform-aws-bc-proxy"
      {% if proxy.origin.smart %}
      origin_domain = "origin-{{ proxy.origin.id }}.{{ proxy.origin.group.group_name }}.smart.{{ smart_zone[:-1] }}"
      {% else %}
      origin_domain = "{{ proxy.origin.domain_name }}"
      {% endif %}
      logging_bucket = module.log_bucket_{{ proxy.origin.group.id }}.bucket_domain_name
      sns_topic_arn = aws_sns_topic.alarms_{{ proxy.origin.group.id }}.arn
      low_bandwidth_alarm = false
      context = module.label_{{ proxy.origin.group.id }}.context
      name = "proxy"
      attributes = ["{{ proxy.origin.domain_name }}"]
      bypass_token = "{{ bypass_token }}"
    }
    {% endfor %}
    """

    def import_state(self, state: Any) -> None:
        if not isinstance(state, dict):
            raise RuntimeError("The Terraform state object returned was not a dict.")
        if "child_modules" not in state['values']['root_module']:
            # There are no CloudFront proxies deployed to import state for
            return
        # CloudFront distributions (proxies)
        for mod in state['values']['root_module']['child_modules']:
            if mod['address'].startswith('module.cloudfront_'):
                for res in mod['resources']:
                    if res['address'].endswith('aws_cloudfront_distribution.this'):
                        proxy = Proxy.query.filter(Proxy.id == mod['address'][len('module.cloudfront_'):]).first()
                        proxy.url = "https://" + res['values']['domain_name']
                        proxy.slug = res['values']['id']
                        proxy.terraform_updated = datetime.datetime.utcnow()
                        break
        # EC2 instances (smart proxies)
        for g in state["values"]["root_module"]["child_modules"]:
            if g["address"].startswith("module.smart_proxy_"):
                group_id = int(g["address"][len("module.smart_proxy_"):])
                for s in g["child_modules"]:
                    if s["address"].endswith(".module.instance"):
                        for x in s["resources"]:
                            if x["address"].endswith(".module.instance.aws_instance.default[0]"):
                                update_smart_proxy_instance(group_id, self.provider, "us-east-2a", x['values']['id'])
        db.session.commit()
