package incheon.cmm.g2f.util;

import java.nio.charset.StandardCharsets;
import java.util.List;

import com.fasterxml.jackson.core.JsonProcessingException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import com.fasterxml.jackson.databind.ObjectMapper;

import incheon.cmm.g2f.sample.vo.*;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class searchApiUtil {

    private final String addressSearchUrl;
    private final String poiSearchUrl;
    private final String coorSearchUrl;
    
    @Autowired private RestTemplate restTemplate;
    @Autowired private ObjectMapper objectMapper;


    public searchApiUtil(
            @Value("${search.api.address.url}") String addressSearchUrl,
            @Value("${search.api.poi.url}") String poiSearchUrl,
            @Value("${search.api.coor.url}") String coorSearchUrl) {
        this.addressSearchUrl = addressSearchUrl;
        this.poiSearchUrl = poiSearchUrl;
        this.coorSearchUrl = coorSearchUrl;
    }

    /**
     * 주소 검색 API 호출
     * @param request 검색 요청
     * @return 검색 결과
     */
    public AddressSearchResponseVO searchAddress(AddressSearchRequestVO request) throws JsonProcessingException {
        log.info("주소 검색 API 호출: keyword={}", request.getKeyword());

        // FormData 형식으로 요청 파라미터 구성
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        formData.add("keyword", request.getKeyword());
        formData.add("currentPage", String.valueOf(request.getCurrentPage()));
        formData.add("countPerPage", String.valueOf(request.getCountPerPage()));
        formData.add("resultType", "json");
        formData.add("firstSort", "none");

        // HTTP 헤더 설정
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        headers.set("Accept-Charset", "UTF-8");

        HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(formData, headers);

        // API 호출
        ResponseEntity<String> response = restTemplate.exchange(
                addressSearchUrl,
                HttpMethod.POST,
                entity,
                String.class
        );

        if (response.getStatusCode() != HttpStatus.OK) {
            throw new RuntimeException("주소 검색 API 호출 실패: " + response.getStatusCode());
        }

        // JSON 파싱
        String responseBody = response.getBody();
        AddressSearchResponseVO result = objectMapper.readValue(responseBody, AddressSearchResponseVO.class);

        // 에러 체크
        if (result.getResults() != null && result.getResults().getCommon() != null) {
            String errorCode = result.getResults().getCommon().getErrorCode();
            if (!"0".equals(errorCode)) {
                String errorMessage = result.getResults().getCommon().getErrorMessage();
                throw new RuntimeException("API 오류 (code=" + errorCode + ", message=" + errorMessage + ")");
            }
        }

        log.info("주소 검색 완료: {}건",
                result.getResults() != null ? result.getResults().getCommon().getTotalCount() : 0);

        return result;

    }

    /**
     * POI 검색 API 호출
     * @param request 검색 요청
     * @return 검색 결과
     */
    public PoiSearchResponseVO searchPoi(PoiSearchRequestVO request) throws JsonProcessingException {
        log.info("POI 검색 API 호출: keyword={}, limit={}, offset={}",
                request.getKeyword(), request.getLimit(), request.getOffset());

        // URL 파라미터 구성
        String url = UriComponentsBuilder.fromHttpUrl(poiSearchUrl)
                .queryParam("keyword", request.getKeyword())
                .queryParam("limit", request.getLimit())
                .queryParam("offset", request.getOffset())
                .encode(StandardCharsets.UTF_8)
                .toUriString();

        // HTTP 헤더 설정
        HttpHeaders headers = new HttpHeaders();
        headers.set("Accept", "application/json");
        headers.set("Accept-Charset", "UTF-8");

        HttpEntity<String> entity = new HttpEntity<>(headers);

        // API 호출
        ResponseEntity<String> response = restTemplate.exchange(
                url,
                HttpMethod.GET,
                entity,
                String.class
        );

        if (response.getStatusCode() != HttpStatus.OK) {
            throw new RuntimeException("POI 검색 API 호출 실패: " + response.getStatusCode());
        }

        // JSON 파싱
        String responseBody = response.getBody();
        PoiSearchResponseVO result = objectMapper.readValue(responseBody, PoiSearchResponseVO.class);

        log.info("POI 검색 완료: {}건 (전체 {}건)",
                result.getHits() != null ? result.getHits().size() : 0,
                result.getTotalHits());

        return result;

    }

    /**
     * 좌표 기반 POI 검색 API 호출
     * @param request 검색 요청
     * @return 검색 결과
     */
    public CoorSearchResponseVO searchPoiByLocation(CoorSearchRequestVO request) throws JsonProcessingException {
        log.info("좌표 기반 POI 검색 API 호출: lat={}, lng={}, limit={}, offset={}",
                request.getLat(), request.getLng(), request.getLimit(), request.getOffset());

        // URL 파라미터 구성
        String url = UriComponentsBuilder.fromHttpUrl(coorSearchUrl)
                .queryParam("lat", request.getLat())
                .queryParam("lng", request.getLng())
                .queryParam("limit", request.getLimit())
                .queryParam("offset", request.getOffset())
                .encode(StandardCharsets.UTF_8)
                .toUriString();

        // HTTP 헤더 설정
        HttpHeaders headers = new HttpHeaders();
        headers.set("Accept", "application/json");
        headers.set("Accept-Charset", "UTF-8");

        HttpEntity<String> entity = new HttpEntity<>(headers);

        // API 호출
        ResponseEntity<String> response = restTemplate.exchange(
                url,
                HttpMethod.GET,
                entity,
                String.class
        );

        if (response.getStatusCode() != HttpStatus.OK) {
            throw new RuntimeException("좌표 검색 API 호출 실패: " + response.getStatusCode());
        }

        // JSON 파싱
        String responseBody = response.getBody();

        // 응답이 배열인지 객체인지 확인
        CoorSearchResponseVO result = new CoorSearchResponseVO();

        if (responseBody.trim().startsWith("[")) {
            // 배열 응답
            List<PoiItemVO> list = objectMapper.readValue(
                    responseBody,
                    objectMapper.getTypeFactory().constructCollectionType(List.class, PoiItemVO.class)
            );
            result.setList(list);
            result.setTotalCount(null); // totalCount 정보 없음
        } else {
            // 객체 응답
            result = objectMapper.readValue(responseBody, CoorSearchResponseVO.class);
        }

        result.setLimit(request.getLimit());
        result.setOffset(request.getOffset());

        log.info("좌표 기반 POI 검색 완료: {}건",
                result.getList() != null ? result.getList().size() : 0);

        return result;

    }
}