data "github_ip_ranges" "allowed_incoming_ranges" {}

# Get team info
data "github_team" "orchard_pull_teams" {
  count        = length(var.github_pull_teams)
  slug         = var.github_pull_teams[count.index]
  summary_only = true
}

data "github_team" "orchard_triage_teams" {
  count        = length(var.github_triage_teams)
  slug         = var.github_triage_teams[count.index]
  summary_only = true
}

data "github_team" "orchard_push_teams" {
  count        = length(var.github_push_teams)
  slug         = var.github_push_teams[count.index]
  summary_only = true
}

# Get user info
data "github_user" "orchaard_pull_request_bypassers" {
  count    = length(var.pull_request_bypassers)
  username = var.pull_request_bypassers[count.index]
}

data "github_user" "orchard_dismissal_restriction" {
  count    = length(var.dismissal_restriction_users)
  username = var.dismissal_restriction_users[count.index]
}

data "github_team" "default_owner" {
  slug         = var.default_code_owner
  summary_only = true
}

locals {
  # The GitHub provider doesn't have a data source for the "current" org configured in the provider,
  # but we can extract it from the repository attributes.
  github_org = split("/", github_repository.orchard_repository.full_name)[0]
}

resource "github_repository" "orchard_repository" {
  name                   = var.repository_name
  visibility             = "private"
  has_issues             = true
  has_projects           = true
  has_wiki               = true
  allow_squash_merge     = var.allow_squash_merge
  allow_merge_commit     = var.allow_merge_commit
  allow_rebase_merge     = var.allow_rebase_merge
  auto_init              = true
  archived               = var.archived_repository
  vulnerability_alerts   = !var.archived_repository
  description            = "${var.description} application_family: ${var.application_family}"
  homepage_url           = var.homepage_url
  has_downloads          = var.has_downloads
  delete_branch_on_merge = var.delete_branch_on_merge

  lifecycle {
    ignore_changes = [
      auto_init,
    ]
  }
}

resource "github_branch_default" "default" {
  repository = github_repository.orchard_repository.name
  branch     = var.default_branch_name
  rename     = var.default_branch_name != "master"

  lifecycle {
    ignore_changes = [
      rename, # Required when importing this resource for a non-default default branch name
    ]
  }
}

resource "github_repository_file" "codeowners" {
  repository          = github_repository.orchard_repository.name
  branch              = github_branch_default.default.branch
  file                = ".github/CODEOWNERS"
  content             = <<EOF
# This file was initially created by the terraform-github module. Subsequent changes should be made directly.
* @${local.github_org}/${data.github_team.default_owner.slug}
EOF
  commit_message      = "Created by Terraform"
  overwrite_on_create = false

  lifecycle {
    ignore_changes = [
      # Subsequent changes to CODEOWNERS file are handled outside of Terraform
      branch,
      commit_message,
      content,
      file,
    ]
  }
}

# Adds triage perms to all repos for all teams
resource "github_team_repository" "team_repo_triage_permissions" {
  for_each   = toset([for team in data.github_team.orchard_triage_teams : team.id])
  team_id    = each.value
  repository = github_repository.orchard_repository.name
  permission = "triage"
}

# Adds pull perms to all repos for all teams
resource "github_team_repository" "team_repo_pull_permissions" {
  for_each   = toset([for team in data.github_team.orchard_pull_teams : team.id])
  team_id    = each.value
  repository = github_repository.orchard_repository.name
  permission = "pull"
}

# Adds push perms to all repos for appropriate teams
resource "github_team_repository" "team_repo_push_permissions" {
  for_each   = toset([for team in data.github_team.orchard_push_teams : team.id])
  team_id    = each.value
  repository = github_repository.orchard_repository.name
  permission = "push"
}

# Adds pull perms for collaborators
resource "github_repository_collaborator" "repo_individual_user_pull_collaborator" {
  count      = length(var.github_repository_pull_collaborators)
  repository = github_repository.orchard_repository.name
  username   = var.github_repository_pull_collaborators[count.index]
  permission = "pull"
}

# Adds push perms to all repos for all collaborators
resource "github_repository_collaborator" "repo_individual_user_push_collaborator" {
  count      = length(var.github_repository_push_collaborators)
  repository = github_repository.orchard_repository.name
  username   = var.github_repository_push_collaborators[count.index]
  permission = "push"
}

# Adds branch protection to all repos in the map with `has_branch_protection` set to true
resource "github_branch_protection" "branch_protection" {
  # checkov:skip=CKV_GIT_5:We required only one reviewer in the established workflow.
  # checkov:skip=CKV_GIT_6:We don't require Git commits to be GPG signed.
  depends_on = [github_repository_file.codeowners]

  for_each = var.branch_protection_enabled ? coalesce(var.branch_protection_patterns, [var.default_branch_name]) : []

  repository_id       = github_repository.orchard_repository.name
  pattern             = each.value
  enforce_admins      = var.branch_protection_enforce_admins
  allows_force_pushes = var.allows_force_pushes

  required_status_checks {
    strict   = var.require_branches_to_be_up_to_date
    contexts = var.required_status_checks
  }

  required_pull_request_reviews {
    dismiss_stale_reviews = var.dismiss_stale_reviews
    restrict_dismissals   = var.restrict_dismissals
    dismissal_restrictions = concat(
      data.github_team.orchard_push_teams.*.node_id,
      flatten([for user in data.github_user.orchard_dismissal_restriction : user.node_id])
    )
    require_code_owner_reviews      = var.github_code_owner_reviews
    pull_request_bypassers          = flatten([for user in data.github_user.orchaard_pull_request_bypassers : user.node_id])
    required_approving_review_count = var.required_approving_review_count
    require_last_push_approval      = var.require_last_push_approval
  }
}

resource "github_repository_custom_property" "repo_custom_property" {
  for_each = {
    application_family = {
      property_value = [var.application_family]
    }
  }

  repository     = github_repository.orchard_repository.name
  property_name  = each.key
  property_type  = "string"
  property_value = each.value.property_value
}

resource "github_repository_autolink_reference" "autolink" {
  for_each = { for idx, ref in var.autolink_references : ref.key_prefix => ref }

  repository          = github_repository.orchard_repository.name
  key_prefix          = each.value.key_prefix
  target_url_template = each.value.target_url_template
  is_alphanumeric     = each.value.is_alphanumeric
}
