terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 5.0"
    }
  }
  backend "s3" {
    bucket = "assessment-model-terraform-state"
    region = "eu-west-2"
    key    = "terraform.tfstate"
  }

  required_version = ">= 1.2.0"
}

provider "aws" {
  region = var.region
}

# Additional provider for resources that need to be in us-east-1, specifically the SSL certificate
provider "aws" {
  alias  = "aws_use1"
  region = "us-east-1"
}

# Assuming the secret is already created and the name is "<stage>/assessment_model/db_credentials"
data "aws_secretsmanager_secret" "db_credentials" {
  name = "${var.stage}/assessment_model/db_credentials"
}

data "aws_secretsmanager_secret_version" "db_credentials" {
  secret_id = data.aws_secretsmanager_secret.db_credentials.id
}

# Default VPC
data "aws_vpc" "default" {
  default = true
}

# For MVP, we allow all inbound traffic to the DB - this will need to be changed later; we'll likely
# need to re-deploy the frontend to AWS so that it's within the same VPC as the DB
resource "aws_security_group" "allow_db" {
  name        = "allow_tls"
  description = "Allow TLS inbound traffic"
  vpc_id      = data.aws_vpc.default.id

  ingress {
    # TLS (change to whatever ports you need)
    from_port   = 5432
    to_port     = 5432
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_db_instance" "default" {
  allocated_storage      = var.allocated_storage
  engine                 = "postgres"
  engine_version         = "14.17"
  instance_class         = var.instance_class
  db_name                = var.database_name
  username               = jsondecode(data.aws_secretsmanager_secret_version.db_credentials.secret_string)["db_assessment_model_username"]
  password               = jsondecode(data.aws_secretsmanager_secret_version.db_credentials.secret_string)["db_assessment_model_password"]
  parameter_group_name   = "default.postgres14"
  skip_final_snapshot    = true
  vpc_security_group_ids = [aws_security_group.allow_db.id]
  lifecycle {
    prevent_destroy = true
  }
  # For the moment, we make the database publically accessible so that we can connect to it from the frontend.
  # We will look to change this in the future but as we are pre-MVP at the time of setting this, we don't
  # have major security demand and don't want to set this up now
  publicly_accessible = true
  # Specify the CA certificate with the default RDS CA certificate
  ca_cert_identifier = "rds-ca-rsa2048-g1"
  # Temporary to enfore immediate change
  apply_immediately = true
  # Set up storage type to gp3 for better performance
  storage_type = "gp3"

  # Automated backups configuration
  backup_retention_period = 14
  backup_window           = "03:00-04:00"
  maintenance_window      = "Sun:02:00-Sun:02:30"
  copy_tags_to_snapshot   = true
  deletion_protection     = true
}

# Set up the bucket that recieve the csv uploads of epc to be retrofit
module "s3_presignable_bucket" {
  source          = "../modules/s3_presignable_bucket"
  bucketname      = "retrofit-plan-inputs-${var.stage}"
  environment     = var.stage
  allowed_origins = var.allowed_origins
}

output "retrofit_plan_trigger_bucket_name" {
  value       = module.s3_presignable_bucket.bucket_name
  description = "Name of the retrofit plan trigger bucket"
}

module "s3_due_considerations_bucket" {
  source          = "../modules/s3_presignable_bucket"
  bucketname      = "retrofit-due-considerations-${var.stage}"
  environment     = var.stage
  allowed_origins = var.allowed_origins
}

module "s3_eco_spreadseet_bucket" {
  source          = "../modules/s3_presignable_bucket"
  bucketname      = "retrofit-eco-spreadsheet-${var.stage}"
  environment     = var.stage
  allowed_origins = var.allowed_origins
}

module "s3" {
  source          = "../modules/s3"
  bucketname      = "retrofit-datalake-${var.stage}"
  allowed_origins = var.allowed_origins
}

output "retrofit_datalake_bucket_id" {
  value = module.s3.bucket_id
}

output "retrofit_datalake_bucket_arn" {
  value = module.s3.bucket_arn
}

output "retrofit_datalake_bucket_domain_name" {
  value = module.s3.bucket_domain_name
}

output "retrofit_datalake_bucket_name" {
  value = module.s3.bucket_name
}

module "model_directory" {
  source          = "../modules/s3"
  bucketname      = "retrofit-model-directory-${var.stage}"
  allowed_origins = var.allowed_origins
}

module "retrofit_sap_predictions" {
  source          = "../modules/s3"
  bucketname      = "retrofit-sap-predictions-${var.stage}"
  allowed_origins = var.allowed_origins
}

output "retrofit_sap_predictions_bucket_name" {
  value       = module.retrofit_sap_predictions.bucket_name
  description = "Name of the retrofit SAP predictions bucket"
}

module "retrofit_sap_data" {
  source          = "../modules/s3"
  bucketname      = "retrofit-data-${var.stage}"
  allowed_origins = var.allowed_origins
}

output "retrofit_sap_data_bucket_name" {
  value       = module.retrofit_sap_data.bucket_name
  description = "Name of the retrofit SAP data bucket"
}

module "retrofit_carbon_predictions" {
  source          = "../modules/s3"
  bucketname      = "retrofit-carbon-predictions-${var.stage}"
  allowed_origins = var.allowed_origins
}

output "retrofit_carbon_predictions_bucket_name" {
  value       = module.retrofit_carbon_predictions.bucket_name
  description = "Name of the retrofit carbon predictions bucket"
}

module "retrofit_heat_predictions" {
  source          = "../modules/s3"
  bucketname      = "retrofit-heat-predictions-${var.stage}"
  allowed_origins = var.allowed_origins
}

output "retrofit_heat_predictions_bucket_name" {
  value       = module.retrofit_heat_predictions.bucket_name
  description = "Name of the retrofit heat predictions bucket"
}

module "retrofit_lighting_cost_predictions" {
  source          = "../modules/s3"
  bucketname      = "retrofit-lighting-cost-predictions-${var.stage}"
  allowed_origins = var.allowed_origins
}

module "retrofit_heating_cost_predictions" {
  source          = "../modules/s3"
  bucketname      = "retrofit-heating-cost-predictions-${var.stage}"
  allowed_origins = var.allowed_origins
}

module "retrofit_hot_water_cost_predictions" {
  source          = "../modules/s3"
  bucketname      = "retrofit-hot-water-cost-predictions-${var.stage}"
  allowed_origins = var.allowed_origins
}

module "retrofit_heating_kwh_predictions" {
  source          = "../modules/s3"
  bucketname      = "retrofit-heating-kwh-predictions-${var.stage}"
  allowed_origins = var.allowed_origins
}

output "retrofit_heating_kwh_predictions_bucket_name" {
  value       = module.retrofit_heating_kwh_predictions.bucket_name
  description = "Name of the retrofit heating kWh predictions bucket"
}

module "retrofit_hotwater_kwh_predictions" {
  source          = "../modules/s3"
  bucketname      = "retrofit-hotwater-kwh-predictions-${var.stage}"
  allowed_origins = var.allowed_origins
}

output "retrofit_hotwater_kwh_predictions_bucket_name" {
  value       = module.retrofit_hotwater_kwh_predictions.bucket_name
  description = "Name of the retrofit hotwater kWh predictions bucket"
}

module "retrofit_sap_baseline_predictions" {
  source          = "../modules/s3"
  bucketname      = "retrofit-sap-baseline-predictions-${var.stage}"
  allowed_origins = var.allowed_origins
}

output "retrofit_sap_baseline_predictions_bucket_name" {
  value       = module.retrofit_sap_baseline_predictions.bucket_name
  description = "Name of the retrofit SAP baseline predictions bucket"
}

module "retrofit_carbon_baseline_predictions" {
  source          = "../modules/s3"
  bucketname      = "retrofit-carbon-baseline-predictions-${var.stage}"
  allowed_origins = var.allowed_origins
}

output "retrofit_carbon_baseline_predictions_bucket_name" {
  value       = module.retrofit_carbon_baseline_predictions.bucket_name
  description = "Name of the retrofit carbon baseline predictions bucket"
}

module "retrofit_heat_baseline_predictions" {
  source          = "../modules/s3"
  bucketname      = "retrofit-heat-baseline-predictions-${var.stage}"
  allowed_origins = var.allowed_origins
}

output "retrofit_heat_baseline_predictions_bucket_name" {
  value       = module.retrofit_heat_baseline_predictions.bucket_name
  description = "Name of the retrofit heat baseline predictions bucket"
}

// We make this bucket presignable, because we want to generate download links for the frontend
module "retrofit_energy_assessments" {
  source             = "../modules/s3_presignable_bucket"
  bucketname         = "retrofit-energy-assessments-${var.stage}"
  allowed_origins    = var.allowed_origins
  environment        = var.stage
  enable_versioning  = true
}

output "retrofit_energy_assessments_bucket_name" {
  value       = module.retrofit_energy_assessments.bucket_name
  description = "Name of the retrofit energy assessments bucket"
}

module "energy_assessments_s3_write" {
  source = "../modules/s3_iam_policy"

  policy_name        = "EnergyAssessmentsWriteS3"
  policy_description = "Allow lambdas to write to retrofit energy assessments bucket"
  bucket_arns        = ["arn:aws:s3:::retrofit-energy-assessments-${var.stage}"]
  actions            = ["s3:PutObject", "s3:AbortMultipartUpload"]
  resource_paths     = ["/*"]
}

output "energy_assessments_s3_write_arn" {
  value = module.energy_assessments_s3_write.policy_arn
}



# Set up the route53 record for the API
module "route53" {
  source         = "../modules/route53"
  domain_name    = var.domain_name
  api_url_prefix = var.api_url_prefix
  providers = {
    aws.aws_use1 = aws.aws_use1
  }
}


# Create an ECR repository for storage of the lambda's docker images
module "ecr" {
  ecr_name = "fastapi-repository-${var.stage}"
  source   = "../modules/ecr"
}

module "lambda_sap_prediction_ecr" {
  ecr_name = "lambda-sap-prediction-${var.stage}"
  source   = "../modules/ecr"
}

module "due_considerations_ecr" {
  ecr_name = "due-considerations-${var.stage}"
  source   = "../modules/ecr"
}

module "eco_spreadsheet_ecr" {
  ecr_name = "eco-spreadsheet-${var.stage}"
  source   = "../modules/ecr"
}

module "lambda_carbon_prediction_ecr" {
  ecr_name = "lambda-carbon-prediction-${var.stage}"
  source   = "../modules/ecr"
}

module "lambda_heat_prediction_ecr" {
  ecr_name = "lambda-heat-prediction-${var.stage}"
  source   = "../modules/ecr"
}

# ECR repos for lighting cost, heating cost and hot water cost models
module "lambda_lighting_cost_prediction_ecr" {
  ecr_name = "lighting-cost-prediction-${var.stage}"
  source   = "../modules/ecr"
}

module "lambda_heating_cost_prediction_ecr" {
  ecr_name = "heating-cost-prediction-${var.stage}"
  source   = "../modules/ecr"
}

module "lambda_hot_water_cost_prediction_ecr" {
  ecr_name = "hot-water-cost-prediction-${var.stage}"
  source   = "../modules/ecr"
}

# For heating and hot water kwh models
module "lambda_heating_kwh_prediction_ecr" {
  ecr_name = "heating-kwh-prediction-${var.stage}"
  source   = "../modules/ecr"
}

module "lambda_hotwater_kwh_prediction_ecr" {
  ecr_name = "hotwater-kwh-prediction-${var.stage}"
  source   = "../modules/ecr"
}

# Baselining models
module "sap_baseline_ecr" {
  ecr_name = "sap-baseline-prediction-${var.stage}"
  source   = "../modules/ecr"
}

module "heat_baseline_ecr" {
  ecr_name = "heat-baseline-prediction-${var.stage}"
  source   = "../modules/ecr"
}

module "carbon_baseline_ecr" {
  ecr_name = "carbon-baseline-prediction-${var.stage}"
  source   = "../modules/ecr"
}

################################################
# SES - Email sending
################################################
module "ses" {
  source      = "../modules/ses"
  domain_name = "domna.homes"
  stage       = var.stage
}

output "ses_dns_records" {
  value = module.ses.dns_records
}

################################################
# Address2UPRN – Lambda ECR
################################################
module "address2uprn_state_bucket" {
  source      = "../modules/tf_state_bucket"
  bucket_name = "address2uprn-terraform-state"

}

module "address2uprn_registry" {
  source = "../modules/container_registry"
  name   = "address2uprn"
  stage  = var.stage

}

# S3 policy for postcode splitter to read from retrofit data bucket
module "address2uprn_s3_read_and_write" {
  source = "../modules/s3_iam_policy"

  policy_name        = "Address2UPRNReadandWriteS3"
  policy_description = "Allow address2uprn Lambda to read and write from retrofit-data bucket"
  bucket_arns        = ["arn:aws:s3:::retrofit-data-${var.stage}"]
  actions            = ["s3:GetObject", "s3:ListBucket", "s3:PutObject"]
  resource_paths     = ["/*"]
}

output "address_2_uprn_s3_read_and_write_arn" {
  value = module.address2uprn_s3_read_and_write.policy_arn
}

################################################
# Condition ETL – Lambda ECR
################################################
module "condition_etl_state_bucket" {
  source      = "../modules/tf_state_bucket"
  bucket_name = "condition-etl-terraform-state"

}

module "condition_etl_registry" {
  source = "../modules/container_registry"
  name   = "condition-etl"
  stage  = var.stage

}

# Condition Data S3 Bucket to store initial data
module "condition_data_bucket" {
  source          = "../modules/s3"
  bucketname      = "condition-data-${var.stage}"
  allowed_origins = var.allowed_origins
}

module "condition_etl_s3_read" {
  source = "../modules/s3_iam_policy"

  policy_name        = "ConditionETLReadS3"
  policy_description = "Allow Lambda to read objects from condition-data-${var.stage}"
  bucket_arns        = ["arn:aws:s3:::condition-data-${var.stage}"]
  actions            = ["s3:GetObject"]
  resource_paths     = ["/*"]
}

output "condition_etl_s3_read_arn" {
  value = module.condition_etl_s3_read.policy_arn
}


################################################
# Postcode Splitter – Lambda ECR
################################################
module "postcode_splitter_state_bucket" {
  source      = "../modules/tf_state_bucket"
  bucket_name = "postcode-splitter-terraform-state"

}

module "postcode_splitter_registry" {
  source = "../modules/container_registry"
  name   = "postcode_splitter"
  stage  = var.stage

}

# S3 policy for postcode splitter to read from retrofit data bucket
module "postcode_splitter_s3_read" {
  source = "../modules/s3_iam_policy"

  policy_name        = "PostcodeSplitterReadS3"
  policy_description = "Allow postcode splitter Lambda to read from retrofit-data bucket"
  bucket_arns        = ["arn:aws:s3:::retrofit-data-${var.stage}"]
  actions            = ["s3:GetObject", "s3:ListBucket", "s3:PutObject"]
  resource_paths     = ["/*"]
}

output "postcode_splitter_s3_read_arn" {
  value = module.postcode_splitter_s3_read.policy_arn
}

################################################
# Bulk Address2UPRN Combiner – Lambda ECR
################################################
module "bulk_address2uprn_combiner_state_bucket" {
  source      = "../modules/tf_state_bucket"
  bucket_name = "bulk-address2uprn-combiner-terraform-state"
}

module "bulk_address2uprn_combiner_registry" {
  source = "../modules/container_registry"
  name   = "bulk_address2uprn_combiner"
  stage  = var.stage
}

module "bulk_address2uprn_combiner_s3" {
  source = "../modules/s3_iam_policy"

  policy_name        = "BulkAddress2UprnCombinerS3"
  policy_description = "Allow bulk_address2uprn_combiner Lambda to read ara_raw_outputs and write bulk_final_outputs"
  bucket_arns        = ["arn:aws:s3:::retrofit-data-${var.stage}"]
  actions            = ["s3:GetObject", "s3:ListBucket", "s3:PutObject"]
  resource_paths     = ["/ara_raw_outputs/*", "/bulk_final_outputs/*"]
}

output "bulk_address2uprn_combiner_s3_arn" {
  value = module.bulk_address2uprn_combiner_s3.policy_arn
}

################################################
# Categorisation – Lambda ECR
################################################
module "categorisation_state_bucket" {
  source      = "../modules/tf_state_bucket"
  bucket_name = "categorisation-terraform-state"

}

module "categorisation_registry" {
  source = "../modules/container_registry"
  name   = "categorisation"
  stage  = var.stage
}


################################################
# OrdnanceSurveyAPI – Lambda
################################################
module "ordnance_state_bucket" {
  source      = "../modules/tf_state_bucket"
  bucket_name = "ordnance-terraform-state"

}

module "ordnance_registry" {
  source = "../modules/container_registry"
  name   = "ordnance"
  stage  = var.stage

}

# S3 policy for postcode splitter to read from retrofit data bucket
module "ordnance_s3_read_and_write" {
  source = "../modules/s3_iam_policy"

  policy_name        = "OrdnanceSurveyReadandWriteS3"
  policy_description = "Allow ordnance Lambda to read and write from retrofit-data bucket"
  bucket_arns        = ["arn:aws:s3:::retrofit-data-${var.stage}"]
  actions            = ["s3:GetObject", "s3:ListBucket", "s3:PutObject"]
  resource_paths     = ["/*"]
}

output "ordnance_s3_read_and_write_arn" {
  value = module.ordnance_s3_read_and_write.policy_arn
}

################################################
# Pas Hub to Ara – Lambda
################################################
module "pashub_to_ara_state_bucket" {
  source      = "../modules/tf_state_bucket"
  bucket_name = "pashub-to-ara-terraform-state"
}

module "pashub_to_ara_registry" {
  source = "../modules/container_registry"
  name   = "pashub_to_ara"
  stage  = var.stage
}

#### TEMP - need to unattach from entities before this can be delete ####
module "pashub_to_ara_s3_write" {
  source = "../modules/s3_iam_policy"

  policy_name        = "PashubToAraWriteS3"
  policy_description = "Allow PasHub to ARA Lambda to write to retrofit energy assessments bucket"
  bucket_arns        = ["arn:aws:s3:::retrofit-energy-assessments-${var.stage}"]
  actions            = ["s3:PutObject", "s3:AbortMultipartUpload"]
  resource_paths     = ["/*"]
}

output "pashub_to_ara_s3_write_arn" {
  value = module.pashub_to_ara_s3_write.policy_arn
}

################################################
# ECMK to Ara – Lambda
################################################
module "ecmk_to_ara_state_bucket" {
  source      = "../modules/tf_state_bucket"
  bucket_name = "ecmk-to-ara-terraform-state"
}

module "ecmk_to_ara_registry" {
  source = "../modules/container_registry"
  name   = "ecmk_to_ara"
  stage  = var.stage
}

################################################
# Engine – Lambda ECR
################################################
module "engine_state_bucket" {
  source      = "../modules/tf_state_bucket"
  bucket_name = "ara-engine-terraform-state"

}

module "engine_registry" {
  source = "../modules/container_registry"
  name   = "engine"
  stage  = var.stage
}

# S3 policy for Engine to read and write from various S3 buckets
module "engine_s3_read_and_write" {
  source = "../modules/s3_iam_policy"

  policy_name        = "EngineReadandWriteS3"
  policy_description = "Allow Engine Lambda to read from and write to various S3 buckets"
  bucket_arns = [
    "arn:aws:s3:::${module.s3_presignable_bucket.bucket_name}",
    "arn:aws:s3:::${module.retrofit_sap_data.bucket_name}",
    "arn:aws:s3:::${module.retrofit_sap_predictions.bucket_name}",
    "arn:aws:s3:::${module.retrofit_carbon_predictions.bucket_name}",
    "arn:aws:s3:::${module.retrofit_heat_predictions.bucket_name}",
    "arn:aws:s3:::${module.retrofit_heating_kwh_predictions.bucket_name}",
    "arn:aws:s3:::${module.retrofit_hotwater_kwh_predictions.bucket_name}",
    "arn:aws:s3:::${module.retrofit_energy_assessments.bucket_name}",
    "arn:aws:s3:::${module.retrofit_sap_baseline_predictions.bucket_name}",
    "arn:aws:s3:::${module.retrofit_carbon_baseline_predictions.bucket_name}",
    "arn:aws:s3:::${module.retrofit_heat_baseline_predictions.bucket_name}"
  ]
  actions        = ["s3:*"]
  resource_paths = ["/*"]
}

output "engine_s3_read_and_write_arn" {
  value = module.engine_s3_read_and_write.policy_arn
}

################################################
# FastAPI – Lambda
################################################
module "ara_fast_api_state_bucket" {
  source      = "../modules/tf_state_bucket"
  bucket_name = "ara-fast-api-terraform-state"
}

output "ara_fast_api_state_bucket" {
  value = module.ara_fast_api_state_bucket.bucket_name
}

# S3 policy for FastAPI app to read and write from various S3 buckets
module "fast_api_s3_read_and_write" {
  source = "../modules/s3_iam_policy"

  policy_name        = "FastAPIReadandWriteS3"
  policy_description = "Allow FastAPI Lambda to read from and write to various S3 buckets"
  bucket_arns = [
    "arn:aws:s3:::${module.s3_presignable_bucket.bucket_name}",
    "arn:aws:s3:::${module.retrofit_sap_data.bucket_name}",
    "arn:aws:s3:::${module.retrofit_sap_predictions.bucket_name}",
    "arn:aws:s3:::${module.retrofit_carbon_predictions.bucket_name}",
    "arn:aws:s3:::${module.retrofit_heat_predictions.bucket_name}",
    "arn:aws:s3:::${module.retrofit_heating_kwh_predictions.bucket_name}",
    "arn:aws:s3:::${module.retrofit_hotwater_kwh_predictions.bucket_name}",
    "arn:aws:s3:::${module.retrofit_energy_assessments.bucket_name}"
  ]
  actions        = ["s3:GetObject", "s3:ListBucket"]
  resource_paths = ["/*"]
}

output "fast_api_s3_read_and_write_arn" {
  value = module.fast_api_s3_read_and_write.policy_arn
}

################################################
# CDN Certificate
################################################
module "cdn_certificate_state_bucket" {
  source      = "../modules/tf_state_bucket"
  bucket_name = "cdn-certificate-terraform-state"
}

output "cdn_certificate_state_bucket" {
  value = module.cdn_certificate_state_bucket.bucket_name
}



################################################
# CDN
################################################
module "cdn_state_bucket" {
  source      = "../modules/tf_state_bucket"
  bucket_name = "ara-cdn-terraform-state"
}

output "cdn_state_bucket" {
  value = module.cdn_state_bucket.bucket_name
}


################################################
# Hubspot ETL Lambda
################################################
module "hubspot_etl_bucket" {
  source      = "../modules/tf_state_bucket"
  bucket_name = "hubspot-etl-bucket-terraform-state"

}

module "hubspot_etl_registry" {
  source = "../modules/container_registry"
  name   = "hubspot-etl"
  stage = var.stage

}

# S3 policy for postcode splitter to read from retrofit data bucket
module "hubspot_etl_s3_read_and_write" {
  source = "../modules/s3_iam_policy"

  policy_name        = "HubspotETLReadandWriteS3"
  policy_description = "Allow hubspot_etl_lambda Lambda to read and write from retrofit-data bucket"
  bucket_arns        = ["arn:aws:s3:::retrofit-data-${var.stage}"]
  actions            = ["s3:GetObject", "s3:ListBucket", "s3:PutObject"]
  resource_paths     = ["/*"]
}

output "hubspot_etl_s3_read_and_write_arn" {
  value = module.hubspot_etl_s3_read_and_write.policy_arn
}


################################################
# MagicPlan Client – Lambda
################################################
module "magic_plan_client_bucket" {
  source      = "../modules/tf_state_bucket"
  bucket_name = "magic-plan-client-terraform-state"
}

module "magic_plan_client_registry" {
  source = "../modules/container_registry"
  name   = "magic-plan"
  stage  = var.stage
}

