package com.fractalite.amad_ndc.convertersRQ;

import java.math.BigInteger;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

import com.amadeus.fmptbq_24_1_1a.*;
import com.amadeus.fmptbq_24_1_1a.FareMasterPricerTravelBoardSearch.FareOptions;
import com.amadeus.fmptbq_24_1_1a.FareMasterPricerTravelBoardSearch.Itinerary;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.fractalite.amad_ndc.services.FlightService;


@Component
public class Fare_MasterPricerTravelBoardSearchRQ {

	private static final Logger LOG = LoggerFactory.getLogger(Fare_MasterPricerTravelBoardSearchRQ.class);
	
	
	public FareMasterPricerTravelBoardSearch buildFareMasterPricerTravelBoardSearch(Map<String, String> searchParams) {

		String travellers  = searchParams.remove("travellers");
		String itineraries = searchParams.remove("Itinerary");
		String cabin       = searchParams.remove("cabin");      // e.g. "ECONOMY", "BUSINESS", "FIRST"
		String ora         = searchParams.remove("ora");        // preferred carrier code e.g. "AF"
		String maxStr      = searchParams.remove("max");        // max number of recommendations
		String directStr   = searchParams.remove("direct");    // "true" or presence in flags
		// remove known params that are not used in SOAP RQ build
		searchParams.remove("currency");
		searchParams.remove("crm");
		searchParams.remove("split");

		if (itineraries == null || itineraries.isBlank()) {
			throw new IllegalArgumentException("Itinerary parameter is required");
		}
		String[] itineraryArray = itineraries.split(",");
		List<FlightService> itineraryList = extractFlightsFromRequest(itineraryArray);

		FareMasterPricerTravelBoardSearch search = new FareMasterPricerTravelBoardSearch();

		// ── Fare Options ──────────────────────────────────────────────────────────
		search.setFareOptions(new FareOptions());
		priceTicketingInfo(search.getFareOptions(), true);

		// ── Number of Units: max results per type ─────────────────────────────────
		int maxResults = 30;
		try { if (maxStr != null && !maxStr.isBlank()) maxResults = Integer.parseInt(maxStr); } catch (NumberFormatException ignored) {}
		search.setNumberOfUnit(new NumberOfUnitsType());
		search.getNumberOfUnit().getUnitNumberDetail().add(createNumberOfUnitDetailsType312621C("PX", 1));
		search.getNumberOfUnit().getUnitNumberDetail().add(createNumberOfUnitDetailsType312621C("NDC", maxResults));
		search.getNumberOfUnit().getUnitNumberDetail().add(createNumberOfUnitDetailsType312621C("RC", maxResults * 3));

		// ── Travellers ────────────────────────────────────────────────────────────
		int paxCounter = 1;
		if (travellers != null && !travellers.isEmpty()) {
			for (String token : travellers.split(",")) {
				String[] parts = token.trim().split(":");
				if (parts.length < 2) continue;
				int count = Integer.parseInt(parts[0].trim());
				String type  = parts[1].trim();
				for (int i = 0; i < count; i++) {
					search.getPaxReference().addAll(paxReference(paxCounter++, type));
				}
			}
		}

		// ── Itineraries ───────────────────────────────────────────────────────────
		search.getItinerary().addAll(createItinerariesFinal(itineraryList));

		// ── Direct flights filter ─────────────────────────────────────────────────
		boolean isDirect = "true".equalsIgnoreCase(directStr);
		if (isDirect) {
			if (search.getTravelFlightInfo() == null) search.setTravelFlightInfo(new TravelFlightInformationType231130S());
			ProductTypeDetailsType120801C productDetails = new ProductTypeDetailsType120801C();
			productDetails.getFlightType().add("N"); // N = Non-stop
			search.getTravelFlightInfo().setFlightDetail(productDetails);
			LOG.info("Direct-flight filter applied");
		}

		// ── Preferred cabin ───────────────────────────────────────────────────────
		if (cabin != null && !cabin.isBlank()) {
			String cabinCode = mapCabinCode(cabin);
			if (cabinCode != null) {
				CabinIdentificationType233500C cid = new CabinIdentificationType233500C();
				cid.setCabinQualifier("PC"); // PC = Preferred Cabin
				cid.getCabin().add(cabinCode);
				if (search.getTravelFlightInfo() == null) search.setTravelFlightInfo(new TravelFlightInformationType231130S());
				search.getTravelFlightInfo().setCabinId(cid);
				LOG.info("Cabin filter applied: {} -> {}", cabin, cabinCode);
			}
		}

		// ── Preferred carrier (ora) ───────────────────────────────────────────────
		if (ora != null && !ora.isBlank()) {
			CompanyIdentificationType315715C ci = new CompanyIdentificationType315715C();
			ci.setCarrierQualifier("RO"); // RO = Requested carrier only
			ci.getCarrierId().add(ora.toUpperCase());
			if (search.getTravelFlightInfo() == null) search.setTravelFlightInfo(new TravelFlightInformationType231130S());
			search.getTravelFlightInfo().getCompanyIdentity().add(ci);
			LOG.info("Preferred carrier filter applied: {}", ora);
		}

		return search;
	}
	
	
		private NumberOfUnitDetailsType312621C createNumberOfUnitDetailsType312621C(String unitType, int value) {
			NumberOfUnitDetailsType312621C ress=new NumberOfUnitDetailsType312621C();
			//ress.setTypeOfUnit("NDC");
			ress.setTypeOfUnit(unitType);

			ress.setNumberOfUnits(new BigInteger(""+value));
			return ress;
		}
		
		private Collection<TravellerReferenceInformationType230874S> paxReference(int paxNumber,String type){
			ArrayList<TravellerReferenceInformationType230874S> paxList=new ArrayList<TravellerReferenceInformationType230874S>();
			ArrayList<TravellerDetailsType> travellerDetailsTypeList =new ArrayList<TravellerDetailsType>();
			TravellerReferenceInformationType230874S pax=new TravellerReferenceInformationType230874S();
			pax.getPtc().add(type);
			TravellerDetailsType travellerDetailsType= new TravellerDetailsType();
			travellerDetailsType.setRef(new BigInteger(""+paxNumber));
			pax.getTraveller().add(travellerDetailsType);
			paxList.add(pax);
			return paxList;
		}
		
	private NumberOfUnitsType createUnitNumberDetail(String unitType, int value) {
		NumberOfUnitsType result = new NumberOfUnitsType();
		NumberOfUnitDetailsType312621C ress=new NumberOfUnitDetailsType312621C();
		ress.setTypeOfUnit("PX");
		ress.setNumberOfUnits(new BigInteger(""+value));
		result.getUnitNumberDetail().add(ress);
		return result;
	}
	
	private void priceFeeIdDescription(FareOptions fareOptions) {
		
		CodedAttributeType231453S feedId=new CodedAttributeType231453S();
		CodedAttributeInformationType316013C element= new CodedAttributeInformationType316013C();
		element.setFeeType("SBF");
		element.setFeeIdNumber("1");
		//CodedAttributeType214155S element =new CodedAttributeType214155S();
		//fareOptions.setFeeIdDescription(element);
	//	PricingTickInfo element = new PricingTickInfo();
		//fareOptions.setPricingTickInfo(element);
		feedId.getFeeId().add(element);
		///feedId.setFeeType("SBF");
		//feedId.setFeeIdNumber("1");

      //   element.getFeeId().add(feedId);
		fareOptions.getFeeIdDescription().getFeeId().add(element);
		
		
		//fareOptions.setFeeIdDescription(element);
		
		
	
		


	}
	
	private void priceTicketingInfo(FareOptions fareOptions, boolean sliceAndDice) {
		PricingTicketingDetailsType element = new PricingTicketingDetailsType();
		fareOptions.setPricingTickInfo(element);

		element.setPricingTicketing(new PricingTicketingInformationType());
		List<String> pricing = element.getPricingTicketing().getPriceType();

		// only request etickets obviously (in case)
		pricing.add("ET");

		// Published fares: RP
		pricing.add("RP");
		//pricing.add("RU");
		// TODO add RU unifares
		/*pricing.add("RU");
		// exclude low cost 
		pricing.add("XLC");

		// ticket-ability precheck
		pricing.add("TAC");
        
		// MTK multiple tickets

		if (sliceAndDice == false) {
			pricing.add("NSD");
		}*/

		// todo make corpid static;
		//String corpo = query.getOtherParamsFirst("corpid");
		
		//log.info("corporate id code : ", corpo);
		//corpo = "020993"; // RAM
		//corpo = "020996"; // RAM
	/*	if (corpo != null) {
			pricing.add("RW");
			CorporateIdentityType corporateId = new CorporateIdentityType();
			corporateId.setCorporateQualifier("RW");
			// "014157" coca cola for tests.
			corporateId.getIdentity().add(corpo);
			fareOptions.setCorporate(new CorporateIdentificationType());
			fareOptions.getCorporate().getCorporateId().add(corporateId);
		}
       log.info("peeee " +query.toString());
		// todo create constant
		if (query.hasFlag("nap")) {
			pricing.add("NAP");
		}
		if (query.hasFlag("npe")) {
			pricing.add("NPE");
		}
		if (query.hasFlag("nr")) {
			pricing.add("NR");
		}
		if (query.hasFlag("rf")) {
			pricing.add("RF");
		}
		if (query.hasFlag("pe")) {
		       log.info("pe14eee ");

			pricing.add("PE");
		}*/
		


	}

	private List<Itinerary> createItinerariesFinal(List<FlightService> itineraryList ) {

		List<Itinerary> result = new ArrayList<Itinerary>();
		int i =1;
			for(FlightService itineraryFlight : itineraryList) {

				FareMasterPricerTravelBoardSearch.Itinerary itinerary = new FareMasterPricerTravelBoardSearch.Itinerary();

				itinerary.setRequestedSegmentRef(new OriginAndDestinationRequestType());
				itinerary.getRequestedSegmentRef().setSegRef(
						new BigInteger("" + i));
				itinerary.setDepartureLocalization(new DepartureLocationType());
				itinerary.getDepartureLocalization().setDeparturePoint(
						new ArrivalLocationDetailsType120834C());
				itinerary.getDepartureLocalization().getDeparturePoint()
						.setLocationId(itineraryFlight.getOrigin());
				itinerary.setArrivalLocalization(new ArrivalLocalizationType());
				itinerary.getArrivalLocalization().setArrivalPointDetails(
						new ArrivalLocationDetailsType());

				itinerary.getArrivalLocalization().getArrivalPointDetails()
						.setLocationId(itineraryFlight.getDestination());
				DateAndTimeInformationType181295S timeDetails = new DateAndTimeInformationType181295S();
				DateAndTimeDetailsTypeI FirstDateTimeDetail = new DateAndTimeDetailsTypeI();
				FirstDateTimeDetail.setDate(convertDate(itineraryFlight.getDepartureDate()));
				timeDetails.setFirstDateTimeDetail(FirstDateTimeDetail);
				itinerary.setTimeDetails(timeDetails);


				result.add(itinerary);
				i++;
			}
		return result;
	}

	/** Maps human-readable cabin name to Amadeus cabin code */
	private String mapCabinCode(String cabin) {
		if (cabin == null) return null;
		switch (cabin.toUpperCase()) {
			case "ECONOMY":         return "M";
			case "PREMIUM_ECONOMY":
			case "PREMIUM ECONOMY": return "W";
			case "BUSINESS":        return "C";
			case "FIRST":           return "F";
			default: return null;
		}
	}


	public static List<FlightService> extractFlightsFromRequest(String[] itineraryArray) {
		List<FlightService> itineraryList = new ArrayList<>();
		for (int j = 0; j < itineraryArray.length; j++) {
			String[] flight = itineraryArray[j].split(":");

			//TODO :remove it later
			String origin = flight[0].substring(0, 3).equalsIgnoreCase("auh")?  "ZVJ"  : flight[0].substring(0, 3) ;
			String destination = flight[0].substring(3, 6).equalsIgnoreCase("auh")? "ZVJ" :  flight[0].substring(3, 6);
			String departureDate = flight[0].substring(6);
			// Simple RQ
			if (flight.length == 1) {
				FlightService itinerary = new FlightService(departureDate, origin, destination);
				itineraryList.add(itinerary);
			}

			// Flight number RQ
			if (flight.length == 2) {
				String flightNumber = flight[1];
				FlightService itinerary = new FlightService(departureDate, origin, destination, flightNumber);
				itineraryList.add(itinerary);
			}

			// Time window RQ
			if (flight.length == 3) {
				String timeBefore = flight[1];
				String timeAfter = flight[2];
				FlightService itinerary = new FlightService(departureDate, origin, destination, timeBefore, timeAfter);
				itineraryList.add(itinerary);
			}

		}

		return itineraryList;
	}


	public static String convertDate(String inputDate) {
		DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
		DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("ddMMyy");

		LocalDate date = LocalDate.parse(inputDate, inputFormatter);
		return date.format(outputFormatter);
	}
}
