voter_statewide_download <- function(output_dir = here::here("../data-raw/voters")) {
  url <- "https://s3.amazonaws.com/dl.ncsbe.gov/data/ncvoter_Statewide.zip"
  fs::dir_create(output_dir)
  path <- fs::path(output_dir, fs::path_file(url))
  download.file(url, path)

  withr::with_dir(output_dir, {
    zip::unzip(fs::path_file(url))
  })

  invisible(fs::path_ext_set(path, "txt"))
}

voter_statewide_convert_parquet <- function(path) {
  path <- fs::path_norm(path)
  path_out <- fs::path_ext_set(tolower(path), "parquet")

  x <- readr::read_tsv(path, col_types = voter_statewide_spec())
  arrow::write_parquet(x, path_out)

  invisible(path_out)
}

voter_statewide_spec <- function() {
  col_state_abbr <- col_factor(
    levels = c(
      state.abb,
      "AP", "DC", "GU", "MP", "NO", "OC", "PR", "UN", "VI"
    )
  )

  codes_status <- c(
    "A" = "ACTIVE",
    "D" = "DENIED",
    "I" = "INACTIVE",
    "R" = "REMOVED",
    "S" = "TEMPORARY"
  )

  codes_race <- c(
    "A" = "ASIAN",
    "B" = "BLACK or AFRICAN AMERICAN",
    "I" = "AMERICAN INDIAN or ALASKA NATIVE",
    "M" = "TWO or MORE RACES ",
    "O" = "OTHER",
    "P" = "NATIVE HAWAIIAN or PACIFIC ISLANDER",
    "U" = "UNDESIGNATED",
    "W" = "WHITE"
  )

  codes_ethnic <- c(
    "HL" = "HISPANIC or LATINO",
    "NL" = "NOT HISPANIC or NOT LATINO",
    "UN" = "UNDESIGNATED"
  )

  codes_gender <- c(
    "F" = "FEMALE",
    "M" = "MALE",
    "U" = "UNDESIGNATED"
  )

  codes_reason <- c(
    "AV" = "VERIFIED",
    "IN" = "CONFIRMATION NOT RETURNED",
    "RD" = "DECEASED",
    "IU" = "CONFIRMATION RETURNED UNDELIVERABLE",
    "DU" = "VERIFICATION RETURNED UNDELIVERABLE",
    "RM" = "REMOVED AFTER 2 FED GENERAL ELECTIONS IN INACTIVE STATUS",
    "RL" = "MOVED FROM COUNTY",
    "RS" = "MOVED FROM STATE",
    "A2" = "CONFIRMATION PENDING",
    "AP" = "VERIFICATION PENDING",
    "DI" = "UNAVAILABLE ESSENTIAL INFORMATION",
    "RF" = "FELONY CONVICTION",
    "RH" = "MOVED WITHIN STATE",
    "RQ" = "REQUEST FROM VOTER",
    "SO" = "OVERSEAS CITIZEN",
    "SM" = "MILITARY",
    "RT" = "TEMPORARY REGISTRANT",
    "RA" = "ADMINISTRATIVE",
    "A1" = "UNVERIFIED"
  )

  cols(
    county_id = col_character(),
    county_desc = col_character(),
    voter_reg_num = col_character(),
    ncid = col_character(),
    last_name = col_character(),
    first_name = col_character(),
    middle_name = col_character(),
    name_suffix_lbl = col_character(),
    status_cd = col_factor(names(codes_status), ordered = TRUE),
    voter_status_desc = col_factor(unname(codes_status), ordered = TRUE),
    reason_cd = col_factor(names(codes_reason)),
    voter_status_reason_desc = col_factor(unname(codes_reason)),
    res_street_address = col_character(),
    res_city_desc = col_character(),
    state_cd = col_state_abbr,
    zip_code = col_character(),
    mail_addr1 = col_character(),
    mail_addr2 = col_character(),
    mail_addr3 = col_character(),
    mail_addr4 = col_character(),
    mail_city = col_character(),
    mail_state = col_state_abbr,
    mail_zipcode = col_character(),
    full_phone_number = col_character(),
    confidential_ind = col_character(),
    registr_dt = col_date(format = "%m/%d/%Y"),
    race_code = col_factor(names(codes_race)),
    ethnic_code = col_factor(names(codes_ethnic)),
    party_cd = col_factor(),
    gender_code = col_factor(names(codes_gender)),
    birth_year = col_integer(),
    age_at_year_end = col_integer(),
    birth_state = col_state_abbr,
    drivers_lic = col_character(),
    precinct_abbrv = col_factor(),
    precinct_desc = col_character(),
    municipality_abbrv = col_factor(),
    municipality_desc = col_character(),
    ward_abbrv = col_factor(),
    ward_desc = col_character(),
    cong_dist_abbrv = col_factor(),
    super_court_abbrv = col_factor(),
    judic_dist_abbrv = col_factor(),
    nc_senate_abbrv = col_factor(),
    nc_house_abbrv = col_factor(),
    county_commiss_abbrv = col_factor(),
    county_commiss_desc = col_character(),
    township_abbrv = col_factor(),
    township_desc = col_character(),
    school_dist_abbrv = col_factor(),
    school_dist_desc = col_character(),
    fire_dist_abbrv = col_factor(),
    fire_dist_desc = col_character(),
    water_dist_abbrv = col_factor(),
    water_dist_desc = col_character(),
    sewer_dist_abbrv = col_factor(),
    sewer_dist_desc = col_character(),
    sanit_dist_abbrv = col_factor(),
    sanit_dist_desc = col_character(),
    rescue_dist_abbrv = col_factor(),
    rescue_dist_desc = col_character(),
    munic_dist_abbrv = col_factor(),
    munic_dist_desc = col_character(),
    dist_1_abbrv = col_factor(),
    dist_1_desc = col_character(),
    vtd_abbrv = col_factor(),
    vtd_desc = col_character()
  )
}

voter_snapshot_list <- function() {
  url <- "https://s3.amazonaws.com/dl.ncsbe.gov/?delimiter=/&prefix=data/Snapshots/"

  res <-
    httr2::request(url) |>
    httr2::req_perform() |>
    httr2::resp_body_xml() |>
    xml2::as_list()

  res <- res$ListBucketResult
  res <- res[which(names(res) == "Contents")]
  res <- map(res, unlist)
  res <- dplyr::bind_rows(res)
  res <- janitor::clean_names(res)
  res$size <- rlang::as_bytes(as.integer(res$size))
  res$url <- paste0("https://s3.amazonaws.com/dl.ncsbe.gov/", res$key)
  res
}

voter_snapshot_download <- function(year, output_dir = here::here("data-raw/voting")) {
  listing <-
    get_voter_snapshot_list() |>
    dplyr::filter(str_detect(key, paste0("VR_Snapshot_", year)))

  if (!nrow(listing)) {
    return(NULL)
  } else if (nrow(listing) > 1) {
    listing <- listing |> dplyr::slice_max(key, n = 1)
  }

  fs::dir_create(output_dir)

  download.file(
    listing$url,
    fs::path(output_dir, fs::path_file(listing$key))
  )
}
