package incheon.res.rdm.com.minwon;


import incheon.res.rdm.com.minwon.vo.InputVO;
import incheon.res.rdm.com.minwon.vo.OutputVO;
import incheon.res.rdm.com.minwon.vo.Sownn00220outVO;
import jakarta.xml.soap.SOAPMessage;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.egovframe.rte.fdl.property.EgovPropertyService;
import org.springframework.stereotype.Component;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.annotation.Resource;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;


@Component("minwonUtil")
public class MinwonUtil {
	
    protected Log log = LogFactory.getLog(this.getClass());
	
    @Resource(name = "propertiesService")
    protected EgovPropertyService propertiesService;

	// 전송할 Message를 생성하고 암호화 한다.
	public String buildXml( InputVO inVO ) throws Exception {
		
		StringBuffer outStr = new StringBuffer();
		outStr.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
		outStr.append("<DOCUMENT>");
		outStr.append("<IFID>"+inVO.getIfid()+"</IFID>");
		outStr.append("<SRCORGCD>"+inVO.getSrcorgcd()+"</SRCORGCD>");
		outStr.append("<TGTORGCD>"+inVO.getTgtorgcd()+"</TGTORGCD>");
		outStr.append("<RESULTCODE>"+inVO.getResultcode()+"</RESULTCODE>");
		outStr.append("<MSGKEY>"+inVO.getMsgkey()+"</MSGKEY>");
		outStr.append("<DATA>");
		
		StringBuffer outs = new StringBuffer();
		outs.append("<message>");
		outs.append("<header>");
		outs.append("<res_cnt>1</res_cnt>");
		outs.append("</header>");
		outs.append("<body>");
		Field[] fields = inVO.getClass().getDeclaredFields();
		for( int i=0; i<fields.length; i++ ) {
			String name = fields[i].getName();
			String value = "";
			if( inVO.getClass().getDeclaredField( fields[i].getName()).get(inVO ) != null){
				value = inVO.getClass().getDeclaredField( fields[i].getName()).get(inVO ).toString() ;
			}
			outs.append("<"+name+">"+ value +"</"+name+">");
		}
		outs.append("</body>");
		outs.append("</message>");

		outStr.append(outs.toString());
		outStr.append("</DATA>");
		outStr.append("</DOCUMENT>");

		log.info("::::: MinwonUtil 시군구 민원 새올 연계 문서 : "+outStr.toString());
		return outStr.toString();

	}
	

	//웹서비스의 리턴결과를 복호화하여 데이터를 읽는다.
	public OutputVO getResultVO(SOAPMessage resSOAPMessage, OutputVO vo , String mngCde) throws Exception{
		TransformerFactory transformerFactory = TransformerFactory.newInstance();
		Transformer transformer = transformerFactory.newTransformer();
		Source sourceContent = resSOAPMessage.getSOAPPart().getContent();
		StringWriter writer = new StringWriter();
		StreamResult result = new StreamResult(writer);
		transformer.transform(sourceContent , result);
		String xmlString = writer.toString();
		log.info("::::: MinwonUtil seol response decoded MsgTag : "+xmlString);

		int beginIndex = xmlString.indexOf("<DATA>");
		int endIndex = xmlString.indexOf("</DATA>");

		xmlString = xmlString.substring(beginIndex+6,endIndex);

		String originalMsgTag = xmlString;
		//String decodedMsgTag = parseData( true, originalMsgTag );
		String decodedMsgTag = originalMsgTag;

		log.info("::::: MinwonUtil seol response decoded MsgTag : "+decodedMsgTag);

		Document decodedMsgDoc = getDocument( decodedMsgTag );
		Element eleFinal = decodedMsgDoc.getDocumentElement();
		NodeList nlFinal = eleFinal.getElementsByTagName( vo.getTag() );

		//NodeList nodeList = nlFinal.item(0).getChildNodes();
		NodeList nodeList = getNodeList(nlFinal, vo, mngCde);
		String NodeValue = "";
		for(int i=0; i<nodeList.getLength(); i++ ) {
			NodeValue = "";
			try{
				NodeValue = nodeList.item(i).getFirstChild().getNodeValue();
			}catch(DOMException e){
				log.error("::::: MinwonUtil getResultVO 중 오류 발생(DOMException.getMessage : "+e.getMessage() + ")");
			}catch(Exception e){
				log.error("::::: MinwonUtil getResultVO 중 오류 발생(Exception.getMessage : "+e.getMessage() + ")");
			}
			//jdk 1.5
			//vo.getClass().getDeclaredField( nodeList.item(i).getNodeName() ).set(vo, nodeList.item(i).getTextContent() );
			try{
				vo.getClass().getDeclaredField( nodeList.item(i).getNodeName() ).set(vo, NodeValue );
			}catch(Exception e){
				log.error("::::: MinwonUtil getResultVO 파싱에러(SownnIcOutputVO 에 필드를 추가하세요) : " + nodeList.item(i).getNodeName() + " = " + NodeValue);
			}
		}

		return vo;
	}
	
	/**
	 * 노드리스트를 가져온다.
	 * 접수부서코드 조회시 구재시의 경우 여러개의 리턴값중에 해당구의 데이터를 뽑아야하므로
	 * 메소드를 따로 뺐음.나머지는 0번째의 값을 가져옴.
	 * @param nlFinal, vo
	 * @return NodeList 
	 */
	private NodeList getNodeList( NodeList nlFinal, OutputVO vo ,String mngCde){
		NodeList rtnList = null;
		if( nlFinal.getLength()>1 && vo.getClass().equals(Sownn00220outVO.class) ){
			for( int i=0; i<nlFinal.getLength(); i++ ){
				String sf_code = getNodeValue(nlFinal.item(i).getChildNodes(), "sf_code");
				if( sf_code.equals( mngCde ) ){
					rtnList = nlFinal.item(i).getChildNodes();
					break;
				}
			}
		}else{
			rtnList = nlFinal.item(0).getChildNodes();
		}
		return rtnList;
	}
	
	/**
	 * nlFinal의 차일드중 nodeName으로 정의된 노드의 값을 리턴
	 * @param nlFinal, nodeName
	 * @return String 
	 */
	private String getNodeValue( NodeList nlFinal, String nodeName ){
		String rtnStr = null;
		for( int i=0; i<nlFinal.getLength(); i++ ){
			String compare = nlFinal.item(i).getNodeName();
			if( nodeName.equals(compare) ){
				rtnStr = nlFinal.item(i).getFirstChild().getNodeValue();
				break;
			}
		}
		return rtnStr;
	}
	

	public String rndData(){
		String DATE_FORMAT = "yyyyMMddHHmmssSSS";
		SimpleDateFormat sdf = new SimpleDateFormat( DATE_FORMAT );
		Calendar cal = Calendar.getInstance();

		Random oRandom = new Random();
		oRandom.setSeed(new Date().getTime());
		
		long rndValue = 0;

		while(true){
			rndValue = Math.abs( oRandom.nextInt() );
			if(String.valueOf(rndValue).length()==8)
				break;
		}

		return sdf.format( cal.getTime() )+rndValue;
	}

	public Document getDocument( String xml ) throws Exception{
		/*Document doc = null ;

		DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();

		InputSource inputSource = new InputSource(new StringReader( inputMsg ));
	    doc =docBuilder.parse( inputSource );

		return doc;
*/
		log.info("getDocument in :::::::::::::::::::::::::::::::::::"+    xml);
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

		// ✅ 핵심: localName이 null 안 나오게 namespace-aware 활성화
		dbf.setNamespaceAware(true);

		dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
		dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
		dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
		dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
		dbf.setXIncludeAware(false);
		dbf.setExpandEntityReferences(false);
		dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
		dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");

		log.info("getDocument in :::::::::::::::::::::::111111111111111111::::::::::::");

		DocumentBuilder db = dbf.newDocumentBuilder();

		log.info("getDocument in :::::::::::::::::::::::2222222:::::::::::");

		// 인코딩/공백 이슈 줄이기
		InputSource is = new InputSource(new StringReader(xml));
		log.info("getDocument in :::::::::::::::::::::::33333333333333333:::::::::::");
		Document doc = db.parse(is);
		doc.getDocumentElement().normalize();


		log.info("doc :::::::::::::::::::::::::::::::::::"+doc);
		return doc;
	}

}
