package incheon.ags.por.service.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;

//import javax.xml.namespace.QName;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;

import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.springframework.stereotype.Service;
import org.w3c.dom.Node;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;

import incheon.ags.por.mapper.PorBoardFileMapper;
import incheon.ags.por.mapper.PorBoardMapper;
import incheon.ags.por.mapper.PorRtmsMapper;
import incheon.ags.por.service.PorBoardFileService;
import incheon.ags.por.service.PorBoardService;
import incheon.ags.por.service.PorExternalService;
import incheon.ags.por.service.PorRtmsService;
import incheon.ags.por.vo.PorBoardFileVO;
import incheon.ags.por.vo.PorRtmsVO;
import incheon.ags.por.vo.kb.PorRtmsInfoVO;
import incheon.ags.por.vo.kb.PorRtmsPriceVO;
import incheon.ags.por.vo.kb.PorRtmsPyongVO;
import incheon.com.cmm.service.FileVO;
import jakarta.xml.ws.BindingProvider;
import jakarta.xml.ws.Dispatch;
import jakarta.xml.ws.handler.MessageContext;
import lombok.RequiredArgsConstructor;

import org.w3c.dom.Node;
import jakarta.xml.ws.*;
import jakarta.xml.ws.handler.MessageContext;

/**
 * 외부자료 관리를 위한 서비스 구현 클래스
 */
@Service("porExternalService")
@RequiredArgsConstructor
public class PorExternalServiceImpl extends EgovAbstractServiceImpl implements PorExternalService {
	
	/**
     * SOAP를 통한 데이터를 조회한다.
     * @param HashMap - 조회할 정보가 담긴 HashMap
     * @return 조회결과
     * @exception Exception
     */
	@Override
    public Map<String, Object> connectSoap(Map<String, String> map) throws Exception {
		
		Map<String, Object> resultMap = new HashMap<String, Object>();
		/*
		// ====== 설정  ======
		// 실제 호출할 엔드포인트 (SOAP service endpoint)
		String endpointUrl = map.get("endpointUrl");
		
		// WSDL URL이 있으면 WSDL을 사용하고, 없으면 Service.create(QName)로도 가능.
		URL wsdlUrl = new URL(map.get("wsdlUrl"));
		
		// WSDL/서비스 네임스페이스와 서비스 이름 (WSDL에 정의된 값으로 맞춰야 함)
		javax.xml.namespace.QName serviceName = new javax.xml.namespace.QName(map.get("qName"), map.get("serviceName"));
		
		// WSDL의 포트 이름 (WSDL에 정의된 port name), 보통 <service><port name="...">
		javax.xml.namespace.QName portName = new javax.xml.namespace.QName(map.get("qName"), map.get("portName"));
		
		// 호출할 오퍼레이션 네임스페이스/이름
		String opNamespace = map.get("operationNameSpace");
		String opName = map.get("operationName");
		
		jakarta.xml.ws.Service service = null;
		
		try {
			service = jakarta.xml.ws.Service.create(wsdlUrl, serviceName);
		}catch(WebServiceException wse) {
			System.err.println("서비스에 연결할 수 없습니다.");
			return resultMap;
		}
		
		// Dispatch 생성: SOAP Message 방식 (MESSAGE)
		Dispatch<SOAPMessage> dispatch = service.createDispatch(portName, SOAPMessage.class, jakarta.xml.ws.Service.Mode.MESSAGE);
		
		// 요청 컨텍스트에 실제 엔드포인트 주소 강제 설정 (WSDL 주소와 다를 때 유용)
		Map<String, Object> rc = dispatch.getRequestContext();
		rc.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointUrl);
		
		// (선택) HTTP headers 세팅 - SOAPAction 등
		Map<String, List<String>> headers = new HashMap<>();
		headers.put("SOAPAction", Collections.singletonList("")); // 필요하면 값 넣기
		rc.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
		
		// SOAPMessage 생성 (SAAJ)
		MessageFactory mf = MessageFactory.newInstance();
		SOAPMessage req = mf.createMessage();
		SOAPEnvelope env = req.getSOAPPart().getEnvelope();
		env.addNamespaceDeclaration("ns", opNamespace);
		
		SOAPBody body = env.getBody();
		javax.xml.namespace.QName bodyName = new javax.xml.namespace.QName(opNamespace, opName, "ns");
		SOAPBodyElement opElement = body.addBodyElement(bodyName);
		// 만약 파라미터가 있다면 아래처럼 추가:
		// opElement.addChildElement("paramName").addTextNode("value");
		
		req.saveChanges();
		
		// 요청 로깅 (디버그)
		System.out.println("----- Request -----");
		printSoapMessage(req);
		
		// 호출
		SOAPMessage resp = dispatch.invoke(req);
		
		// 응답 로깅
		System.out.println("----- Response -----");
		printSoapMessage(resp);
		
		// 응답 바디에서 결과 추출 (간단 추출)
		SOAPBody respBody = resp.getSOAPBody();
		if (respBody.hasFault()) {
		    System.err.println("SOAP Fault: " + respBody.getFault().getFaultString());
		} else {
		    // 첫번째 요소 텍스트 얻기 (서비스 반환이 문자열(JSON 포함)일 때)
		    Node firstChild = respBody.getFirstChild();
		    if (firstChild != null) {
		        String text = firstChild.getTextContent().trim();
		        JSONParser parser = new JSONParser();
		        JSONArray array = (JSONArray) parser.parse(text);
		        
		        resultMap.put("list", array);
		        
		    } else {
		        System.out.println("Response body empty");
		    }
		}*/
        
        return resultMap;
        
    }
	
	/**
     * HTTPUrlConnection를 통한 데이터를 조회한다.
     * @param HashMap - 조회할 정보가 담긴 HashMap
     * @return 조회결과
     * @exception Exception
     */
	@Override
    public Map<String, Object> connectUrl(Map<String, Object> map) throws Exception {
    	
    	Map<String, Object> resultMap = new HashMap<String, Object>();
    	
    	String path = String.valueOf(map.get("path"));
    	String query = String.valueOf(map.get("query"));
    	String method = String.valueOf(map.get("method"));
    	
    	Map<String, String> requestProperties = (Map<String, String>) map.get("requestProperties");
    	
    	URL url = new URL(path + "?" + query);
    	HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    	
    	connection.setRequestMethod(method);
//    	connection.setRequestProperty("Content-Type", "application/json");
    	if(requestProperties != null && requestProperties.size() > 0) {
    		requestProperties.forEach((k, v) -> {
    			System.out.println(k + " : " + v);
    			connection.setRequestProperty(k, v);
    		});
    	}
    	connection.setDoOutput(true);
		connection.setDoInput(true);
		System.out.println(connection.getURL());
		System.out.println(connection.getRequestProperties());
		connection.connect();
		
		BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
		StringBuilder response = new StringBuilder();
		String line;
		
		while ((line = reader.readLine()) != null) {
			response.append(line);
		}
		reader.close();
		resultMap.put("data", response.toString());
		
    	return resultMap;
    }
    
	/*private void printSoapMessage(SOAPMessage msg) {
	    try {
	        TransformerFactory tFactory = TransformerFactory.newInstance();
	        Transformer transformer = tFactory.newTransformer();
	        // remove standalone "xml declaration" if any
	        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
	        Source source = msg.getSOAPPart().getContent();
	        StreamResult result = new StreamResult(System.out);
	        transformer.transform(source, result);
	        System.out.println(); // newline
	    } catch (Exception e) {
	        e.printStackTrace();
	    }
	}*/
	
	
	////////////////////////////////////////////////////////////////////////////////////////// 데이터 테스트
	public String kras000002() throws Exception {
    	return readText("kras000002");
    }
    
    public String kras000026() throws Exception {
    	return readText("kras000026");
    }
    
    public String kras000028() throws Exception {
    	return readText("kras000028");			// 권한 없어서 데이터 못받음
    }
    
    public String kras000030() throws Exception {
    	return readText("kras000030");
    }
    
    public String cais4001() throws Exception {
    	return readText("cais4001");
    }
    
    public String cais4002() throws Exception {
    	return readText("cais4002");
    }
    
    public String cais4003() throws Exception {
    	return readText("cais4003");
    }
    
    public String cais4004() throws Exception {
    	return readText("cais4004");
    }
    
    public String gData() throws Exception {
    	return readText("gData");
    }
    
    public String korep() throws Exception {
    	return readText("korep");
    }
    
    private String readText(String name) throws IOException {
    	
    	File file = new File("src/main/resources/static/por/file/" + name + ".json");
    	BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "utf-8"));
    	
    	StringBuffer sb = new StringBuffer("");
    	
    	String s;
    	while((s = br.readLine()) != null) {
    		sb.append(s);
    	}
    	
    	br.close();
    	
    	return sb.toString();
    }
    
} 