package incheon.cmm.g2f.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.http.*;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class PoiManagerUtil {

    private final RestTemplate restTemplate;
    private final String baseUrl;
    private final ObjectMapper objectMapper;

    public PoiManagerUtil(RestTemplate restTemplate, String baseUrl) {
        this.restTemplate = restTemplate;
        this.baseUrl = baseUrl;
        this.objectMapper = new ObjectMapper();
    }

    /**
     * ID로 POI 조회
     * @param id POI ID
     * @return POI 정보 또는 에러 메시지
     */
    public Map<String, Object> getPoiById(Integer id) {
        try {
            String url = baseUrl + "/id";
            
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("id", id);
            
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);
            
            log.info("POI 조회 요청: ID={}", id);
            ResponseEntity<Map> response = restTemplate.postForEntity(url, entity, Map.class);
            
            Map<String, Object> result = response.getBody();
            if (result != null && result.containsKey("message")) {
                log.warn("POI 조회 결과: {}", result.get("message"));
            } else {
                log.info("POI 조회 성공: ID={}", id);
            }
            
            return result;
        } catch (HttpClientErrorException e) {
            log.error("POI 조회 실패: ID={}, 상태코드={}, 응답={}", id, e.getStatusCode(), e.getResponseBodyAsString());
            Map<String, Object> errorResult = new HashMap<>();
            errorResult.put("error", true);
            errorResult.put("message", e.getResponseBodyAsString());
            return errorResult;
        } catch (Exception e) {
            log.error("POI 조회 예외 발생: ID={}", id, e);
            Map<String, Object> errorResult = new HashMap<>();
            errorResult.put("error", true);
            errorResult.put("message", "POI 조회 예외 발생");
            return errorResult;
        }
    }

    /**
     * POI 추가
     * @param poiData POI 데이터 (name, road_addr, jibun_addr, cat1, cat2, cat3, cat4, lat, lng)
     * @return 생성된 POI 정보
     */
    public Map<String, Object> addPoi(Map<String, Object> poiData) {
        try {
            String url = baseUrl + "/add";
            
            String json = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(poiData);
            log.info("POI 추가 요청:\n{}", json);
            
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<Map<String, Object>> entity = new HttpEntity<>(poiData, headers);
            
            ResponseEntity<Map> response = restTemplate.postForEntity(url, entity, Map.class);
            Map<String, Object> result = response.getBody();
            
            log.info("POI 추가 성공: {}", objectMapper.writeValueAsString(result));
            return result;
        } catch (HttpClientErrorException e) {
            log.error("POI 추가 실패: 상태코드={}, 응답={}", e.getStatusCode(), e.getResponseBodyAsString());
            throw new RuntimeException("POI 추가 실패: " + e.getResponseBodyAsString(), e);
        } catch (Exception e) {
            log.error("POI 추가 예외 발생", e);
            throw new RuntimeException("POI 추가 예외", e);
        }
    }

    /**
     * POI 수정
     * @param poiData POI 데이터 (id 포함 필수)
     * @return 수정 성공 여부
     */
    public boolean updatePoi(Map<String, Object> poiData) {
        try {
            if (!poiData.containsKey("id")) {
                log.error("POI 수정 실패: id가 필요합니다");
                return false;
            }
            
            String url = baseUrl + "/update";
            
            String json = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(poiData);
            log.info("POI 수정 요청:\n{}", json);
            
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<Map<String, Object>> entity = new HttpEntity<>(poiData, headers);
            
            ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
            
            if (response.getStatusCode().is2xxSuccessful()) {
                log.info("POI 수정 성공: ID={}, 응답={}", poiData.get("id"), response.getBody());
                return true;
            } else {
                log.error("POI 수정 실패: ID={}, 상태코드={}, 응답={}", 
                    poiData.get("id"), response.getStatusCode(), response.getBody());
                return false;
            }
        } catch (HttpClientErrorException e) {
            log.error("POI 수정 실패: 상태코드={}, 응답={}", e.getStatusCode(), e.getResponseBodyAsString());
            return false;
        } catch (Exception e) {
            log.error("POI 수정 예외 발생", e);
            return false;
        }
    }

    /**
     * 전체 POI 목록 조회
     * @param limit 페이지당 조회할 데이터 수 (기본값 10)
     * @param offset 시작 위치 (기본값 0)
     * @return POI 목록과 페이징 정보
     */
    public Map<String, Object> getAllPois(Integer limit, Integer offset) {
        try {
            if (limit == null) limit = 10;
            if (offset == null) offset = 0;
            
            String url = UriComponentsBuilder
                .fromHttpUrl(baseUrl + "/get")
                .queryParam("limit", limit)
                .queryParam("offset", offset)
                .toUriString();
            
            log.info("전체 POI 조회 요청: limit={}, offset={}", limit, offset);
            
            ResponseEntity<Map> response = restTemplate.getForEntity(url, Map.class);
            Map<String, Object> result = response.getBody();
            
            if (result != null) {
                log.info("전체 POI 조회 성공: estimatedTotalHits={}, hitsPerPage={}, totalPages={}", 
                    result.get("estimatedTotalHits"), 
                    result.get("hitsPerPage"),
                    result.get("totalPages"));
            }
            
            return result;
        } catch (DataAccessException e) {
            log.error("전체 POI 조회 실패: limit={}, offset={}", limit, offset, e);
            return Collections.emptyMap();
        }
    }

    /**
     * 키워드로 POI 검색
     * @param keyword 검색 키워드
     * @param limit 페이지당 조회할 데이터 수 (기본값 8)
     * @param offset 시작 위치 (기본값 0)
     * @return 검색된 POI 목록과 페이징 정보
     */
    public Map<String, Object> searchPoiByKeyword(String keyword, Integer limit, Integer offset) {
        try {
            if (limit == null) limit = 8;
            if (offset == null) offset = 0;
            
            String url = UriComponentsBuilder
                .fromHttpUrl(baseUrl + "/poi/keyword")
                .queryParam("keyword", keyword)
                .queryParam("limit", limit)
                .queryParam("offset", offset)
                .toUriString();
            
            log.info("키워드 검색 요청: keyword={}, limit={}, offset={}", keyword, limit, offset);
            
            ResponseEntity<Map> response = restTemplate.getForEntity(url, Map.class);
            Map<String, Object> result = response.getBody();
            
            if (result != null) {
                log.info("키워드 검색 성공: keyword={}, totalHits={}, totalPages={}, hitsPerPage={}", 
                    keyword,
                    result.get("totalHits"), 
                    result.get("totalPages"),
                    result.get("hitsPerPage"));
            }
            
            return result;
        } catch (DataAccessException e) {
            log.error("키워드 검색 실패: keyword={}, limit={}, offset={}", keyword, limit, offset, e);
            return Collections.emptyMap();
        }
    }

    /**
     * POI 삭제 (존재할 경우)
     * @param id POI ID
     * @return 삭제 성공 여부
     */
    public boolean deletePoi(Integer id) {
        try {
            String url = baseUrl + "/delete/" + id;
            
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<Void> entity = new HttpEntity<>(headers);
            
            log.info("POI 삭제 요청: ID={}", id);
            ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
            
            if (response.getStatusCode().is2xxSuccessful()) {
                log.info("POI 삭제 성공: ID={}", id);
                return true;
            } else {
                log.error("POI 삭제 실패: ID={}, 상태코드={}", id, response.getStatusCode());
                return false;
            }
        } catch (DataAccessException e) {
            log.error("POI 삭제 예외 발생: ID={}", id, e);
            return false;
        }
    }
}