package com.fractalite.amad_ndc.convertersRQ;


import java.util.*;

import com.amadeus.travelManagement.amadeus.xml._2010._06.travel_offerpricerq_v1.AMATravelOfferPriceRQ;
import com.amadeus.travelManagement.amadeus.xml._2010._06.travel_offerpricerq_v1.*;
import org.springframework.stereotype.Component;

@Component
public class AMA_OfferPriceRQ {

	/**
	 * Main entry point.
	 *
	 * @param offer  the encoded offer string (internalId / uniqueOfferReference / offerItems)
	 * @param paxes  the paxes param, e.g. "PAX1:ADT;PAX2:ADT;PAX3:CHD"
	 */
	public AMATravelOfferPriceRQ buildAMA_TravelOfferPriceRQ(String offer, String paxes) {

		AMATravelOfferPriceRQ offerPriceRQ = new AMATravelOfferPriceRQ();
		offerPriceRQ.setParty(buildPartyType());

		// Parse the offer string
		Map<String, Object> parsed = parseReference(offer);

		String internalId            = (String) parsed.get("internalId");
		String uniqueOfferReference  = (String) parsed.get("uniqueOfferReference");
		// offerItemsById: PTC -> single offerItemId  (one per PTC type from the offer string)
		Map<String, String> offerItemsById = (Map<String, String>) parsed.get("offerItems");

		// Parse individual passengers: [ {paxId:"PAX1", ptc:"ADT"}, ... ]
		List<Map<String, String>> passengers = parsePaxes(paxes);

		System.out.println("internalId            : " + internalId);
		System.out.println("uniqueOfferReference  : " + uniqueOfferReference);
		System.out.println("offerItems            : " + offerItemsById);
		System.out.println("passengers            : " + passengers);

		offerPriceRQ.setRequest(buildRequestType(uniqueOfferReference, offerItemsById, internalId, passengers));
		return offerPriceRQ;
	}

	// -------------------------------------------------------------------------
	// Party
	// -------------------------------------------------------------------------

	public PartyType buildPartyType() {
		PartyType party = new PartyType();
		SenderType sender = new SenderType();
		TravelAgencyType travelAgencyType = new TravelAgencyType();
		travelAgencyType.setAgencyID("unused");
		travelAgencyType.setPseudoCityID("unused");
		sender.setTravelAgency(travelAgencyType);
		party.setSender(sender);
		return party;
	}

	// -------------------------------------------------------------------------
	// Request
	// -------------------------------------------------------------------------

	public RequestType buildRequestType(
			String uniqueOfferReference,
			Map<String, String> offerItemsById,
			String internalId,
			List<Map<String, String>> passengers) {

		RequestType requestType = new RequestType();

		// --- DataLists / PaxList ---
		DataListsType dataListsType = new DataListsType();
		PaxListType paxListType = new PaxListType();

		for (Map<String, String> pax : passengers) {
			PaxType paxType = new PaxType();
			paxType.setPaxID(pax.get("paxId"));
			paxType.setPTC(pax.get("ptc"));
			paxListType.getPax().add(paxType);
		}

		dataListsType.setPaxList(paxListType);
		requestType.setDataLists(dataListsType);

		// --- PricedOffer ---
		requestType.setPricedOffer(
				buildPricedOffer(uniqueOfferReference, offerItemsById, internalId, passengers)
		);

		return requestType;
	}

	// -------------------------------------------------------------------------
	// PricedOffer
	// -------------------------------------------------------------------------

	public CreateOrderType buildPricedOffer(
			String uniqueOfferReference,
			Map<String, String> offerItemsById,
			String internalId,
			List<Map<String, String>> passengers) {

		CreateOrderType pricedOffer = new CreateOrderType();

		SelectedOfferType selectedOfferType = new SelectedOfferType();
		selectedOfferType.setShoppingResponseRefID(internalId);
		selectedOfferType.setOfferRefID(uniqueOfferReference);
		selectedOfferType.setOwnerCode("AF");

		/*
		 * Group passengers by PTC so we can attach all paxRefIDs
		 * that share the same offerItemId under a single SelectedOfferItem.
		 *
		 *  e.g.  ADT -> [PAX1, PAX2]  => one SelectedOfferItem with offerItemId for ADT
		 *        CHD -> [PAX3]         => one SelectedOfferItem with offerItemId for CHD
		 */
		Map<String, List<String>> ptcToPaxIds = new LinkedHashMap<>();

		for (Map<String, String> pax : passengers) {
			String ptc   = pax.get("ptc");
			String paxId = pax.get("paxId");
			ptcToPaxIds.computeIfAbsent(ptc, k -> new ArrayList<>()).add(paxId);
		}

		for (Map.Entry<String, List<String>> entry : ptcToPaxIds.entrySet()) {
			String ptc        = entry.getKey();
			List<String> paxIds = entry.getValue();
			String offerItemId = offerItemsById.get(ptc);

			if (offerItemId == null) {
				System.err.println("WARNING: no offerItemId found for PTC " + ptc);
				continue;
			}

			SelectedOfferItemType selectedOfferItem = new SelectedOfferItemType();
			selectedOfferItem.setOfferItemRefID(offerItemId);
			selectedOfferItem.getPaxRefID().addAll(paxIds);  // attach ALL pax of this PTC

			selectedOfferType.getSelectedOfferItem().add(selectedOfferItem);
		}

		pricedOffer.getSelectedOffer().add(selectedOfferType);
		return pricedOffer;
	}

	// -------------------------------------------------------------------------
	// Parsers
	// -------------------------------------------------------------------------

	/**
	 * Parses the paxes query param into an ordered list of {paxId, ptc} maps.
	 * Input example: "PAX1:ADT;PAX2:ADT;PAX3:CHD"
	 */
	public List<Map<String, String>> parsePaxes(String paxes) {
		List<Map<String, String>> result = new ArrayList<>();
		if (paxes == null || paxes.isEmpty()) return result;

		for (String token : paxes.split(";")) {
			token = token.trim();
			if (token.contains(":")) {
				String[] kv = token.split(":", 2);
				Map<String, String> pax = new LinkedHashMap<>();
				pax.put("paxId", kv[0].trim());
				pax.put("ptc",   kv[1].trim());
				result.add(pax);
			}
		}
		return result;
	}

	/**
	 * Parses the encoded offer string.
	 * Returns:
	 *   "internalId"           -> String
	 *   "uniqueOfferReference" -> String
	 *   "offerItems"           -> Map<String, String>  (PTC -> offerItemId)
	 */
	public Map<String, Object> parseReference(String reference) {
		Map<String, Object> result      = new HashMap<>();
		Map<String, String> offerItemsMap = new LinkedHashMap<>();

		if (reference == null || reference.isEmpty()) {
			result.put("offerItems", offerItemsMap);
			return result;
		}

		// We need to handle the offerItems section specially because it also uses '*' as delimiter
		// Strategy: split on '*' but collect offerItems tokens manually.

		String[] parts = reference.split("\\*");
		boolean inOfferItems = false;

		for (String part : parts) {

			if (part.startsWith("internalId:")) {
				result.put("internalId", part.substring("internalId:".length()));
				inOfferItems = false;

			} else if (part.startsWith("uniqueOfferReference:")) {
				result.put("uniqueOfferReference", part.substring("uniqueOfferReference:".length()));
				inOfferItems = false;

			} else if (part.startsWith("offerItems:")) {
				inOfferItems = true;
				// First item is on the same token: offerItems:[ADT]#id
				String itemsPart = part.substring("offerItems:".length());
				parseOfferItem(itemsPart, offerItemsMap);

			} else if (inOfferItems && part.contains("#")) {
				// Subsequent [PTC]#id tokens after offerItems:
				parseOfferItem(part, offerItemsMap);

			} else {
				inOfferItems = false;
			}
		}

		result.put("offerItems", offerItemsMap);
		return result;
	}

	/** Parses a single "[PTC]#offerItemId" token into the map. */
	private void parseOfferItem(String item, Map<String, String> map) {
		item = item.trim();
		if (item.contains("#") && item.contains("[") && item.contains("]")) {
			String ptc = item.substring(item.indexOf('[') + 1, item.indexOf(']'));
			String id  = item.substring(item.indexOf('#') + 1);
			map.put(ptc, id);
		}
	}
}



