package com.fractalite.amad_ndc.services;

import java.io.File;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.TimeZone;
import java.util.UUID;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
//import com.amadeus.wsdl._2010._06.*;

import com.amadeus.xml._2010._06.travel_offerpricerq_v1.*;
//import com.amadeus.xml._2010._06.session_v3.Session;
import com.amadeus.xml.fmptbq_24_1_1a.FareMasterPricerTravelBoardSearch;



//import com.amadeus.integration.HeaderServices.CustomWebServiceException;



@Service
public class HeadersServices {
    private final Logger LOG = LoggerFactory.getLogger(HeadersServices.class);

   // @Value("${ndc_endpoint}")
///    public String endpoint="https://nodeD1.test.webservices.amadeus.com/1ASIWALSFRX";
    public String endpoint=" https://noded5.test.webservices.amadeus.com/1ASIWALSFRX";
    @Value("${wsap_username}")
    public String username;

    @Value("${wsap.password}")
    public String password;

    @Value("${wsap.agentDutyCode}")
    public String agentDutyCode;

    @Value("${wsap.requestorType}")
    public String requestorType;

    @Value("${wsap.POSType}")
    public String POSType;

    @Value("${wsap.officeID}")
    public String officeID;

    private int requestCounter = 0;



  

    public SOAPHeader startHeaderLess(SOAPMessage soapMessage,String action) throws SOAPException, JAXBException, DatatypeConfigurationException, IOException, TransformerException {


        SOAPHeader header = soapMessage.getSOAPHeader();

        header.addNamespaceDeclaration("add","http://www.w3.org/2005/08/addressing");


        // Addressing elements
        String messageId = UUID.randomUUID().toString();

        String to = endpoint;

        // Add the <add:MessageID>, <add:Action>, and <add:To> elements directly to the <soapenv:Header>
        SOAPElement messageIdElement = header.addChildElement("MessageID", "add");
        messageIdElement.setTextContent(messageId);

        SOAPElement actionElement = header.addChildElement("Action", "add");
        actionElement.setTextContent(action);

        SOAPElement toElement = header.addChildElement("To", "add");
        toElement.setTextContent(to);


        /////////////password////////////////

        // Generate a new nonce
        String nonce = generateNonce();
        

        // Generate a timestamp
        String timestamp = generateTimestamp();


        // Calculate the result
        byte[] result = shaTk1Nonce(nonce, timestamp, password);
        String resultBase64 = Base64.getEncoder().encodeToString(result);
        //////////////////////////////////////

        SOAPElement securityElement = header.addChildElement("Security", "oas",
                "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");

        securityElement.addNamespaceDeclaration("oas1","http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

        SOAPElement usernameToken = securityElement.addChildElement("UsernameToken", "oas");

        SOAPElement usernameElement = usernameToken.addChildElement("Username", "oas");
        usernameElement.setTextContent(username);

        SOAPElement nonceElement  = usernameToken.addChildElement("Nonce", "oas");
       // nonceElement.setAttributeNS(null, "EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wsssoap-message-security-1.0#Base64Binary");
        nonceElement.setTextContent(nonce);

        SOAPElement passwordElement   = usernameToken.addChildElement("Password", "oas");
        passwordElement.setAttributeNS(null,"Type","http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest");
        passwordElement.setTextContent(resultBase64);

        SOAPElement created   = usernameToken.addChildElement("Created", "oas1");
        created.setTextContent(timestamp);


        ////////////////securityHostUser
        SOAPElement securityHostedUser = header.addChildElement("AMA_SecurityHostedUser","sec","http://xml.amadeus.com/2010/06/Security_v1");


        SOAPElement userID  = securityHostedUser.addChildElement("UserID","sec");
        userID.setAttributeNS(null, "AgentDutyCode", agentDutyCode);
        userID.setAttributeNS(null, "RequestorType", requestorType);
        userID.setAttributeNS(null, "PseudoCityCode", officeID);
        userID.setAttributeNS(null, "POS_Type", POSType);

        /////////////////////////////////
        //System.out.println(header.toString());


        return header;
    }

    public SOAPMessage getFareMasterPricerTravelBoardSearchRQ(FareMasterPricerTravelBoardSearch fareMasterPricerTravelBoardSearch) throws SOAPException, JAXBException, DatatypeConfigurationException, IOException, TransformerException, CustomWebServiceException {
        MessageFactory messageFactory = MessageFactory.newInstance();
        SOAPMessage soapMessage = messageFactory.createMessage();
        JAXBContext jaxbContext = JAXBContext.newInstance(FareMasterPricerTravelBoardSearch.class);

        SOAPPart soapPart = soapMessage.getSOAPPart();
        SOAPEnvelope envelope = soapPart.getEnvelope();
        //envelope.addNamespaceDeclaration("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
        //envelope.addNamespaceDeclaration("ns4", "http://webservices.amadeus.com/PNRRET_09_1_1A"); // Namespace for PNR_Retrieve element

        SOAPHeader header = startHeaderLess(soapMessage,"http://webservices.amadeus.com/FMPTBQ_24_1_1A");
        SOAPBody soapBody = soapMessage.getSOAPBody();



        MimeHeaders headers = soapMessage.getMimeHeaders();
        headers.addHeader("Content-Type", "text/xml; charset=utf-8");
        headers.addHeader("SOAPAction", "http://webservices.amadeus.com/FMPTBQ_24_1_1A");
       // headers.addHeader("SOAPAction", "http://webservices.amadeus.com/1ASIWALSFRX/FMPTBQ_24_1_1A");

        

        QName _GetRateDetails_QNAME = new QName("http://webservices.amadeus.com/FMPTBQ_24_1_1A", "FareMasterPricerTravelBoardSearch", "");

        JAXBElement<FareMasterPricerTravelBoardSearch> fareMasterPricerTravelBoardSearchObject =
                new JAXBElement<FareMasterPricerTravelBoardSearch>(_GetRateDetails_QNAME, FareMasterPricerTravelBoardSearch.class, null, fareMasterPricerTravelBoardSearch);

        jaxbContext.createMarshaller().marshal(fareMasterPricerTravelBoardSearchObject, soapBody);

        soapMessage.saveChanges();
        
        //test save logs
       // String requestFolderPath = createRequestFolder();

        // Generate a unique filename within the request folder
        //String fileName = "PNRRetrieveRQ_" + System.currentTimeMillis() + ".xml";
      //  String filePath = requestFolderPath + File.separator + fileName;

        // Save SOAP message response to file
      //  saveSoapMessageToFile(soapMessage, filePath);
        LOG.info("Search query: ",soapMessage.toString());
        soapMessage.writeTo(System.out);
        
        LOG.info("Search query:: ",soapMessage.toString());

       // callSoapWebServicePNR(soapMessage);
    //    String faultString = soapMessage.getSOAPBody().getFault().getFaultString();
        callSoapWebService(endpoint,soapMessage);
        return soapMessage;
    }

    

    public SOAPMessage getOfferPrice(AMATravelOfferPriceRQ offerPriceRQ) throws SOAPException, JAXBException, DatatypeConfigurationException, IOException, TransformerException, CustomWebServiceException {
        MessageFactory messageFactory = MessageFactory.newInstance();
        SOAPMessage soapMessage = messageFactory.createMessage();
        JAXBContext jaxbContext = JAXBContext.newInstance(AMATravelOfferPriceRQ.class);

        SOAPPart soapPart = soapMessage.getSOAPPart();
        SOAPEnvelope envelope = soapPart.getEnvelope();
        //envelope.addNamespaceDeclaration("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
        //envelope.addNamespaceDeclaration("ns4", "http://webservices.amadeus.com/PNRRET_09_1_1A"); // Namespace for PNR_Retrieve element

        SOAPHeader header = startHeaderLess(soapMessage,"http://webservices.amadeus.com/Travel_OfferPrice_1.2");
        SOAPBody soapBody = soapMessage.getSOAPBody();



        MimeHeaders headers = soapMessage.getMimeHeaders();
        headers.addHeader("Content-Type", "text/xml; charset=utf-8");
       // headers.addHeader("SOAPAction", "http://webservices.amadeus.com/FMPTBQ_24_1_1A");
        headers.addHeader("SOAPAction", "http://webservices.amadeus.com/1ASIWALSFRX/_2010._06.travel_offerpricerq_v1");

        

        QName _GetRateDetails_QNAME = new QName("http://webservices.amadeus.com/_2010._06.travel_offerpricerq_v1", "AMA_TravelOfferPriceRQ", "");

        JAXBElement<AMATravelOfferPriceRQ> offerPriceRQObject =
                new JAXBElement<AMATravelOfferPriceRQ>(_GetRateDetails_QNAME, AMATravelOfferPriceRQ.class, null, offerPriceRQ);

        jaxbContext.createMarshaller().marshal(offerPriceRQObject, soapBody);

        soapMessage.saveChanges();
        //test save logs
       // String requestFolderPath = createRequestFolder();

        // Generate a unique filename within the request folder
        //String fileName = "PNRRetrieveRQ_" + System.currentTimeMillis() + ".xml";
      //  String filePath = requestFolderPath + File.separator + fileName;

        // Save SOAP message response to file
      //  saveSoapMessageToFile(soapMessage, filePath);

        soapMessage.writeTo(System.out);
       // callSoapWebServicePNR(soapMessage);
    //    String faultString = soapMessage.getSOAPBody().getFault().getFaultString();
        callSoapWebService(endpoint,soapMessage);
        return soapMessage;
    }
        
        
        public SOAPMessage callSoapWebServicePNR(SOAPMessage soapMessage) throws  CustomWebServiceException {


            SOAPConnectionFactory soapConnectionFactory;
            try {
                soapConnectionFactory = SOAPConnectionFactory.newInstance();
                SOAPConnection soapConnection = soapConnectionFactory.createConnection();

                // Update the endpoint URL
                // String endpointURL = endpoint;

                try {
                    SOAPMessage soapResponse = soapConnection.call(soapMessage, endpoint);

                    if (soapResponse.getSOAPBody().getFault() != null) {
                        String faultString = soapResponse.getSOAPBody().getFault().getFaultString();
                        System.out.println("Error: " + faultString);

                        if (faultString.contains("INVALID RECORD LOCATOR")) {
                            System.out.println("Ignoring INVALID RECORD LOCATOR error.");
                            soapConnection.close();
                            return null;
                        }
                    } else {
                        // Normal response handling




                        System.out.println("Response SOAP Message:");
                        soapResponse.writeTo(System.out);
                        System.out.println();

               

                        soapConnection.close();

                        return soapResponse;
                    }
                } catch (SOAPException e) {
                    // Handle SOAPException separately
                    System.out.println("\n SOAPException occurred: " + e.getMessage());
                    soapConnection.close();
                    return null;
                }
            } catch (IOException |  SOAPException e) {
                e.printStackTrace();
                //throw new CustomWebServiceException("\nAn error occurred during the SOAP call: " + e.getMessage());
            }

          

        
        
        
        
        
        
        
        return soapMessage;
    }
        
        
        
        
        private static void callSoapWebService(String soapEndpointUrl, SOAPMessage soapRequest) {
            try {
                // Create SOAP Connection
                SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
                SOAPConnection soapConnection = soapConnectionFactory.createConnection();

                // Send SOAP Message to SOAP Server
                //SOAPMessage soapRequest = createSOAPRequest(soapAction);
                SOAPMessage soapResponse = soapConnection.call(soapRequest, soapEndpointUrl);

                // Print the SOAP Response
                System.out.println("Response SOAP Message:");
                soapResponse.writeTo(System.out);
                System.out.println();

                soapConnection.close();
            } catch (Exception e) {
                System.err.println("\nError occurred while sending SOAP Request to Server!\nMake sure you have the correct endpoint URL and SOAPAction!\n");
                e.printStackTrace();
            }
        }

        /*  private static SOAPMessage createSOAPRequest(String soapAction) throws Exception {
            MessageFactory messageFactory = MessageFactory.newInstance();
            SOAPMessage soapMessage = messageFactory.createMessage();

            createSoapEnvelope(soapMessage);

            MimeHeaders headers = soapMessage.getMimeHeaders();
            headers.addHeader("SOAPAction", soapAction);

            soapMessage.saveChanges();

           //  Print the request message, just for debugging purposes 
            System.out.println("Request SOAP Message:");
            soapMessage.writeTo(System.out);
            System.out.println("\n");

            return soapMessage;
        }*/


    public String generateNonce() {
            SecureRandom secureRandom = new SecureRandom();
            byte[] nonceBytes = new byte[16]; 
            secureRandom.nextBytes(nonceBytes);
            LOG.info("nonce1 "+secureRandom);

           // return nonceBytes.toString();
            return Base64.getEncoder().encodeToString(nonceBytes);
        }
    

    public String generateTimestamp() {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
        Date now = new Date();
        return dateFormat.format(now);
    }

        public byte[] shaTk1Nonce(String nonce, String timestamp, String pwd) {
            try {
                MessageDigest sha1 = MessageDigest.getInstance("SHA-1");

                // Compute SHA-1 hash of the password
                byte[] shaPwd = sha1.digest(pwd.getBytes());

                // Decode the nonce from Base64
                LOG.info("nonce "+Base64.getDecoder().decode(nonce));
                byte[] decodedNonce = Base64.getDecoder().decode(nonce);
                
                // Update the SHA-1 hash with nonce, timestamp, and password hash
                sha1.reset();
                sha1.update(decodedNonce);
                sha1.update(timestamp.getBytes());
                sha1.update(shaPwd);

                // Calculate the final SHA-1 hash
                return sha1.digest();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
                return null;
            }
        }

    public class CustomWebServiceException extends Exception {
        public CustomWebServiceException(String message) {
            super(message);
        }
    }

    // Define a custom exception class for handling the "INVALID RECORD LOCATOR" error
    class CustomInvalidRecordLocatorException extends Exception {
        public CustomInvalidRecordLocatorException(String message) {
            super(message);
        }
    }

    private void saveSoapMessageToFile(SOAPMessage soapMessage, String filePath) throws TransformerException, IOException, SOAPException {
        // Convert SOAPMessage to XML string
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        StreamResult result = new StreamResult(new File(filePath));
        transformer.transform(soapMessage.getSOAPPart().getContent(), result);
    }

   /* private String createRequestFolder() {
        requestCounter++;
        String requestFolderPath = logsDirectoryPath + File.separator + "Request_" + requestCounter;

        File folder = new File(requestFolderPath);
        if (!folder.exists()) {
            folder.mkdirs(); // Create the directory and any missing parent directories
        }

        return requestFolderPath;
    }*/
}
