locals {
  granted_account_roles  = toset(concat([local.warehouse_access_role], var.additional_roles, local.additional_warehouse_access_roles))
  granted_database_roles = toset(var.additional_database_roles)
}

# A functional role (the default role of the user) is created for the service user
resource "snowflake_account_role" "service_user_role" {
  name    = "${upper(var.environment)}_${upper(replace(var.service_name, "-", "_"))}_SERVICE_USER_ROLE"
  comment = "Managed by Terraform"
}

# On the user, we just set the minimal config necessary
# The optional properties such as firstname, lastname, password etc are not required for service users
# Any additional warehouses and roles are added in the role grants
resource "snowflake_user" "service_user" {
  name              = "${upper(var.environment)}_${upper(replace(var.service_name, "-", "_"))}_SERVICE_USER"
  default_warehouse = local.warehouse
  default_role      = snowflake_account_role.service_user_role.name
  rsa_public_key    = var.rsa_public_key
}

# The provided roles in var.additional_roles (mostly these will be object access roles),
# a default warehouse access role (as determined by the workload type/access pattern in var.readonly),
# and any additional warehouse access roles (if additional warehouse names provided),
# are granted to the service user role created above
resource "snowflake_grant_account_role" "account_roles" {
  for_each         = local.granted_account_roles
  role_name        = each.value
  parent_role_name = snowflake_account_role.service_user_role.name
}

# Grants for the object roles defined on the database level.
resource "snowflake_grant_database_role" "database_roles" {
  for_each = local.granted_database_roles

  database_role_name = each.value
  parent_role_name   = snowflake_account_role.service_user_role.name
}

# The new service user role is explicitly granted to the SYSADMIN role, and the service user
resource "snowflake_grant_account_role" "grant_service_user_role_to_roles" {
  role_name        = snowflake_account_role.service_user_role.name
  parent_role_name = "SYSADMIN"
}

resource "snowflake_grant_account_role" "grant_service_user_role_to_users" {
  role_name = snowflake_account_role.service_user_role.name
  user_name = snowflake_user.service_user.name
}

# Our convention is to give ownership of both the role and the user to USERADMIN
resource "snowflake_grant_ownership" "service_user_role_ownership_grant" {
  account_role_name   = "USERADMIN"
  outbound_privileges = "COPY"
  on {
    object_type = "ROLE"
    object_name = snowflake_account_role.service_user_role.name
  }
}

resource "snowflake_grant_ownership" "service_user_user_ownership_grant" {
  account_role_name   = "USERADMIN"
  outbound_privileges = "COPY"
  on {
    object_type = "USER"
    object_name = snowflake_user.service_user.name
  }
}

resource "snowflake_user_authentication_policy_attachment" "service_user_auth_policy_attachment" {
  authentication_policy_name = "\"SNOWFLAKE_SETTINGS\".\"AUTHENTICATION_POLICIES\".\"service_users_authentication_policy\""
  user_name                  = snowflake_user.service_user.name
}
