"""
Bootstrap's user's development environment by creating cloud resources required by SAM CLI
"""

import json
import logging
from typing import Optional

import boto3
from botocore.exceptions import ClientError

from samcli import __version__
from samcli.cli.global_config import GlobalConfig
from samcli.commands.exceptions import CredentialsError, UserException
from samcli.lib.utils.managed_cloudformation_stack import StackOutput
from samcli.lib.utils.managed_cloudformation_stack import manage_stack as manage_cloudformation_stack

SAM_CLI_STACK_NAME = "aws-sam-cli-managed-default"
LOG = logging.getLogger(__name__)


def manage_stack(profile, region):
    outputs: StackOutput = manage_cloudformation_stack(
        profile=None, region=region, stack_name=SAM_CLI_STACK_NAME, template_body=_get_stack_template()
    )

    bucket_name = outputs.get("SourceBucket")
    if bucket_name is None:
        msg = (
            "Stack " + SAM_CLI_STACK_NAME + " exists, but is missing the managed source bucket key. "
            "Failing as this stack was likely not created by the AWS SAM CLI."
        )
        raise UserException(msg)
    # This bucket name is what we would write to a config file
    return bucket_name


def get_current_account_id(profile: Optional[str] = None):
    """Returns account ID based on used AWS credentials."""
    session = boto3.Session(profile_name=profile)
    sts_client = session.client("sts")
    try:
        caller_identity = sts_client.get_caller_identity()
    except ClientError as ex:
        if ex.response["Error"]["Code"] == "InvalidClientTokenId":
            raise CredentialsError("Cannot identify account due to invalid configured credentials.") from ex
        raise CredentialsError("Cannot identify account based on configured credentials.") from ex
    if "Account" not in caller_identity:
        raise CredentialsError("Cannot identify account based on configured credentials.")
    return caller_identity["Account"]


def _get_stack_template():
    gc = GlobalConfig()
    template = {
        "AWSTemplateFormatVersion": "2010-09-09",
        "Transform": "AWS::Serverless-2016-10-31",
        "Description": "Managed Stack for AWS SAM CLI",
        "Metadata": {
            "SamCliInfo": {
                "version": __version__,
                "installationId": gc.installation_id if gc.installation_id else "unknown",
            }
        },
        "Resources": {
            "SamCliSourceBucket": {
                "Type": "AWS::S3::Bucket",
                "Properties": {
                    "PublicAccessBlockConfiguration": {
                        "BlockPublicPolicy": "true",
                        "BlockPublicAcls": "true",
                        "IgnorePublicAcls": "true",
                        "RestrictPublicBuckets": "true",
                    },
                    "BucketEncryption": {
                        "ServerSideEncryptionConfiguration": [
                            {"ServerSideEncryptionByDefault": {"SSEAlgorithm": "aws:kms"}}
                        ]
                    },
                    "VersioningConfiguration": {"Status": "Enabled"},
                    "Tags": [{"Key": "ManagedStackSource", "Value": "AwsSamCli"}],
                },
            },
            "SamCliSourceBucketBucketPolicy": {
                "Type": "AWS::S3::BucketPolicy",
                "Properties": {
                    "Bucket": {"Ref": "SamCliSourceBucket"},
                    "PolicyDocument": {
                        "Statement": [
                            {
                                "Action": ["s3:GetObject"],
                                "Effect": "Allow",
                                "Resource": {
                                    "Fn::Join": [
                                        "",
                                        [
                                            "arn:",
                                            {"Ref": "AWS::Partition"},
                                            ":s3:::",
                                            {"Ref": "SamCliSourceBucket"},
                                            "/*",
                                        ],
                                    ]
                                },
                                "Principal": {"Service": "serverlessrepo.amazonaws.com"},
                                "Condition": {"StringEquals": {"aws:SourceAccount": {"Ref": "AWS::AccountId"}}},
                            },
                            {
                                "Action": ["s3:*"],
                                "Effect": "Deny",
                                "Resource": [
                                    {
                                        "Fn::Join": [
                                            "",
                                            [
                                                "arn:",
                                                {"Ref": "AWS::Partition"},
                                                ":s3:::",
                                                {"Ref": "SamCliSourceBucket"},
                                            ],
                                        ]
                                    },
                                    {
                                        "Fn::Join": [
                                            "",
                                            [
                                                "arn:",
                                                {"Ref": "AWS::Partition"},
                                                ":s3:::",
                                                {"Ref": "SamCliSourceBucket"},
                                                "/*",
                                            ],
                                        ]
                                    },
                                ],
                                "Principal": "*",
                                "Condition": {"Bool": {"aws:SecureTransport": "false"}},
                            },
                        ]
                    },
                },
            },
        },
        "Outputs": {"SourceBucket": {"Value": {"Ref": "SamCliSourceBucket"}}},
    }
    return json.dumps(template)
