# ==========================================
# 1. 필수 패키지 불러오기
# ==========================================
library(sf)
library(tidyverse)
library(lubridate)
library(sfhotspot)
library(leaflet)
library(htmlwidgets)
library(osmdata)

# ==========================================
# 2. 범죄 데이터 2년치 & 배경 경계선 불러오기
# ==========================================
# 범죄 데이터 불러오기
folder_path <- "/Users/JeanChoi/Downloads/Met Police two years"
all_files <- list.files(path = folder_path, pattern = "*.csv", full.names = TRUE, recursive = TRUE)
crime_raw <- map_df(all_files, read_csv)
crime_clean <- crime_raw %>% filter(!is.na(Longitude) & !is.na(Latitude))

# 배경 경계선 불러오기 (미리 4326 좌표계로 맞춤)
bid_file <- "/Users/JeanChoi/Downloads/business_improvement_districts-2/business_improvement_districts.shp"
northbank_bid <- st_read(bid_file, quiet = TRUE) %>% filter(bid_name == "Northbank BID") %>% st_transform(4326)

ward_file <- "/Users/JeanChoi/Downloads/data/wards/London_Ward_Boundaries.shp"
target_wards <- st_read(ward_file, quiet = TRUE) %>% filter(BOROUGH %in% c("Westminster", "City of London", "Camden")) %>% st_transform(4326)

# ==========================================
# 3. 범죄 데이터 자르기 & 핫스팟(KDE) 만들기
# ==========================================
# 초고속 필터링 (네모 박스로 1차 자르기)
bbox_4326 <- st_bbox(northbank_bid)
crime_fast <- crime_clean %>%
  filter(Longitude >= bbox_4326["xmin"] & Longitude <= bbox_4326["xmax"] &
         Latitude >= bbox_4326["ymin"] & Latitude <= bbox_4326["ymax"])

# 정확한 구역으로 2차 자르기 (영국 좌표계 27700 사용)
crime_sf <- st_as_sf(crime_fast, coords = c("Longitude", "Latitude"), crs = 4326) %>% st_transform(27700)
northbank_bid_27700 <- northbank_bid %>% st_transform(27700)
crime_target_area <- st_intersection(crime_sf, northbank_bid_27700)

# 🌟 핫스팟 계산 🌟
kde_total <- sfhotspot::hotspot_kde(crime_target_area, cell_size = 50, bandwidth_adjust = 1, quiet = TRUE) %>% st_as_sf()

# ==========================================
# 4. OSM 장소(POI) 가져오기
# ==========================================
get_poi_all <- function(key, value) {
  tryCatch({
    res <- opq(bbox = bbox_4326, timeout = 200) %>%
      add_osm_feature(key = key, value = value) %>%
      osmdata_sf()
    pts <- res$osm_points %>% filter(!is.na(name)) %>% select(name)
    polys <- res$osm_polygons %>% filter(!is.na(name)) %>% st_centroid() %>% select(name)
    combined <- rbind(pts, polys)
    return(combined)
  }, error = function(e) { return(NULL) })
}

amenities_final <- get_poi_all('amenity', c('restaurant', 'pub', 'embassy', 'cinema'))
hotels_final <- get_poi_all('tourism', 'hotel')

# ==========================================
# 5. 지도용 좌표계(4326)로 완벽 통일
# ==========================================
kde_4326 <- st_transform(kde_total, 4326)
wards_4326 <- target_wards
bid_4326 <- northbank_bid

# POI는 데이터가 잘 찾아졌을 때만 좌표 변환 (에러 방지 안전장치)
if (!is.null(amenities_final) && nrow(amenities_final) > 0) {
  amenities_4326 <- st_transform(amenities_final, 4326)
} else {
  amenities_4326 <- NULL
}

if (!is.null(hotels_final) && nrow(hotels_final) > 0) {
  hotels_4326 <- st_transform(hotels_final, 4326)
} else {
  hotels_4326 <- NULL
}

# ==========================================
# 6. 마스터 지도 조립 (절대 안 꼬이게 토막토막 안전하게 조립!)
# ==========================================
# 색상 팔레트 오류 방지 (강제로 숫자로 인식시킴)
pal_kde <- colorNumeric(palette = "YlOrRd", domain = as.numeric(kde_4326$kde), na.color = "transparent")

# 1단계: 배경과 핫스팟 그리기
master_map <- leaflet() %>%
  addProviderTiles(providers$CartoDB.Positron, group = "Light Base (기본)") %>%
  addTiles(group = "OSM Base (상세)") %>%
  addPolygons(data = kde_4326, fillColor = ~pal_kde(as.numeric(kde)), fillOpacity = 0.6, 
              color = "transparent", weight = 0, group = "Crime Heatmap (핫스팟)") %>%
  addPolygons(data = bid_4326, fill = FALSE, color = "red", weight = 3, group = "Northbank BID") %>%
  addPolygons(data = wards_4326, fill = FALSE, color = "#005f73", weight = 2, group = "Ward Boundaries")

# 2단계: 식당/펍 마커 추가
if (!is.null(amenities_4326)) {
  master_map <- master_map %>%
    addCircleMarkers(data = amenities_4326, color = "#3182bd", radius = 5, fillOpacity = 0.8,
                     stroke = FALSE, popup = ~name, group = "Amenities (식당/펍 등)",
                     clusterOptions = markerClusterOptions())
}

# 3단계: 호텔 마커 추가
if (!is.null(hotels_4326)) {
  master_map <- master_map %>%
    addCircleMarkers(data = hotels_4326, color = "#756bb1", radius = 5, fillOpacity = 0.8,
                     stroke = FALSE, popup = ~name, group = "Hotels (호텔)",
                     clusterOptions = markerClusterOptions())
}

# 4단계: 레이어 컨트롤과 범례 추가
master_map <- master_map %>%
  addLayersControl(
    baseGroups = c("Light Base (기본)", "OSM Base (상세)"),
    overlayGroups = c("Northbank BID", "Ward Boundaries", "Crime Heatmap (핫스팟)", 
                      "Amenities (식당/펍 등)", "Hotels (호텔)"),
    options = layersControlOptions(collapsed = FALSE)
  ) %>%
  addLegend(pal = pal_kde, values = as.numeric(kde_4326$kde), title = "Crime Density", position = "bottomright")

# 최종 지도 화면에 딱!
master_map