package com.gridnine.xtrip.server.reports.templates

import com.gridnine.xtrip.common.Environment
import com.gridnine.xtrip.common.gds.model.DailySalesReportParameters
import com.gridnine.xtrip.common.gds.rules.Actions
import com.gridnine.xtrip.common.gds.amadeus.model.AmadeusGdsAccount
import com.gridnine.xtrip.common.midoffice.model.SalesContext
import com.gridnine.xtrip.common.model.EntityContainer
import com.gridnine.xtrip.common.model.EntityReference
import com.gridnine.xtrip.common.model.booking.BookingFile
import com.gridnine.xtrip.common.model.booking.PassengerTypeValue
import com.gridnine.xtrip.common.model.booking.ProductIndex
import com.gridnine.xtrip.common.model.booking.ProductStatus
import com.gridnine.xtrip.common.model.booking.air.Product
import com.gridnine.xtrip.common.model.dict.GdsName
import com.gridnine.xtrip.common.model.dict.Gender
import com.gridnine.xtrip.common.model.entity.EntityStorage
import com.gridnine.xtrip.common.model.helpers.BookingHelper
import com.gridnine.xtrip.common.model.helpers.DictHelper
import com.gridnine.xtrip.common.rules.RuleRestriction
import com.gridnine.xtrip.common.rules.RuleResult
import com.gridnine.xtrip.common.rules.RuleSettings
import com.gridnine.xtrip.server.ibus.IntegrationBusFacade

createStyle(name: 'title',fontBold: true, h_span: 14, h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight:20)
createStyle(name: 'header',fontBold: false,  h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight:10, leftBorder:'MEDIUM', rightBorder:'MEDIUM', topBorder:'MEDIUM', bottomBorder:'MEDIUM', wrapText: true)
createStyle(name: 'data',fontBold: false,  h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight:10, leftBorder:'THIN', rightBorder:'THIN', topBorder:'THIN', bottomBorder:'THIN')
createStyle(name: 'textData',parent: 'data')
createStyle(name: 'error', foreground: 'YELLOW', h_alignment : 'CENTER')

//*** Сверка продаж BSP в ГДС AMADEUS
def printersMap = ['БСПКОРП':'RU', 'BSP':'RU', '555A':'AT', 'BSPA':'AT'];

def es = EntityStorage.get();
def dateBegin = parameters['key-report-params']['periodBegin']
def reportDate = new java.text.SimpleDateFormat("dd.MM.yyyy").format(dateBegin);
def salesPoint = parameters['salesPoint']
def salesContext = new SalesContext();
def trace = parameters['trace']
salesContext.setSalesPoint(salesPoint);

//def printers = ["RU", "AT"]

class PccStruct2 {
    String pcc
    EntityContainer gdsAccount

    public int hashCode() {
        return Arrays.deepHashCode([pcc, gdsAccount].toArray())
    }

    public boolean equals(Object other) {
        if (other == null) {
            return false
        }
        if (this.getClass() != other.getClass()) {
            return false
        }
        PccStruct2 otherStruct = other
        return this.pcc = otherStruct.pcc && this.gdsAccount == otherStruct.gdsAccount
    }

    public String toString() {
        return "pcc=${pcc}, gdsAccount=${gdsAccount.entity.name}[${gdsAccount.entity.uid}]"
    }
}

Closure<PccStruct2> getPccStruct = {EntityContainer gdsAccount, String pcc ->
    PccStruct2 result = new PccStruct2()
    result.pcc = pcc
    result.gdsAccount = gdsAccount
    return result
}

Closure<Collection<PccStruct2>> getPccStructs = {
    def result = [] as Set
    for (RuleSettings rs : es.resolve(salesPoint).getEntity().getRuleSet().getRules()) {
        List gdsAccountCnts = []
        for (RuleRestriction restriction : rs.restrictions) {
            if (restriction.propertyId == 'GDS_ACCOUNT') {
                Collection gdsAccountRefs = restriction.value
                for (EntityReference gdsAccountRef : gdsAccountRefs) {
                    EntityContainer gdsAccountCnt = EntityStorage.get().resolve(gdsAccountRef)
                    if (gdsAccountCnt == null || !(gdsAccountCnt.entity instanceof AmadeusGdsAccount)) {
                        continue
                    }
                    gdsAccountCnts.add(gdsAccountCnt)
                }
            }
        }
        if (gdsAccountCnts.empty) {
            continue
        }
        String pccResult = null

        boolean isBsp = false
        for (RuleResult rr : rs.results) {
            if (rr.action == Actions.TICKETING_PCC) {
                pccResult = rr.value
            } else if (rr.action.toString() == 'BLANK_OWNER') {
                isBsp = true
            }
        }

        if (!isBsp) {
            continue
        }

        for (EntityContainer gdsAccountCnt : gdsAccountCnts) {
            result.add(getPccStruct(gdsAccountCnt, pccResult))
        }
    }

    return result
}

def pccs = getPccStructs()

def momData = [:]
def bookingFilesWithNoTicketNumbers = []
def momVoidedData = [:]

String getCarrierNumber(ProductIndex index) {
    if (index.carrierNumber == null) {
        BookingFile bookingFile = EntityStorage.get().resolve(index.source)?.entity
        if (bookingFile == null) {
            return null
        }
        Product product = BookingHelper.findProductByUid(index.navigationKey, bookingFile)
        if (product == null) {
            return null
        }
        return product.carrierNumber
    }
    return index.carrierNumber
}

tickets{

    if(it.ticketNumbers.size()==0){
        bookingFilesWithNoTicketNumbers.add(it
                .getBookingNumber());
    }
    else {
        String carrierNumber = getCarrierNumber(it)
        //String ticketNumber = carrierNumber.concat(GroovyCollections.min(it.ticketNumbers))


        if (carrierNumber == null) {
            return
        }

        if (it.ticketNumbers.contains('2482854147')) {
            warn 'ticket : ' + it.ticketNumbers + ', carrierNumber: ' + carrierNumber + ', status: ' + it.status
        }
        if (it.status == ProductStatus.VOID) {
            def numbers = it.ticketNumbers.iterator()
            while (numbers.hasNext()) momVoidedData[carrierNumber.concat(numbers.next())] = it
        } else {
            //warn 'momData[' + ticketNumber + '] = ' + it
            /*if (ticketNumber.contains('/')) {
                boolean conj = true
                def index = ticketNumber.indexOf('/')
                String firstTicket = ticketNumber.substring(0, index)
                String secondTicket = ticketNumber.substring(0, index - 1) + ticketNumber.substring(index + 1)
                momData[firstTicket] = it
                momData[secondTicket] = it
            } else {*/
            def numbers = it.ticketNumbers.iterator()
            while (numbers.hasNext()) momData[carrierNumber.concat(numbers.next())] = it
        }
    }
}

def amadeusReportData = [:]
def pccByTicketNumber = [:]
def relevantPccs = parameters['pcc'].tokenize(',').collect { it.trim() }

pccs.findAll { relevantPccs.contains(it.pcc) || relevantPccs.isEmpty() }.each{ PccStruct2 it ->
    info 'Processing PCC ' + it.pcc
    def dailyReportParameters = new DailySalesReportParameters();
    dailyReportParameters.date = dateBegin
    if (it.pcc != null) {
        dailyReportParameters.pcc = it.pcc
    } else {
        dailyReportParameters.pcc = it.gdsAccount.entity.primaryPCC
    }
    dailyReportParameters.trace = trace
    try {
        dailyReportParameters.includeVoided = true
    } catch (Exception e) {
        warn ("error 1: ${e.message}")
    }

    warn 'it.gdsAccount: ' + it.gdsAccount
    warn 'dailyReportParameters.pcc: ' + dailyReportParameters.pcc
    warn 'dailyReportParameters.date: ' + dailyReportParameters.date
    warn 'it.gdsAccount.entity.name: ' + it.gdsAccount.entity.name

    def data = [:]
    data['GDS'] = GdsName.AMADEUS
    data['GDS_ACCOUNT'] = it.gdsAccount
    data['DAILY_SALES_REPORT_PARAMETERS']= dailyReportParameters
    data['SALES_CONTEXT']= salesContext
    def routeName = 'gds:amadeus:daily-sales-report:daily-sales-report-custom-settings'

    try{
        Environment.getPublished(IntegrationBusFacade.class).processRouteSync(routeName, data);
    }
    catch(Exception e){
        def msg = e.cause?.message;
        if(msg?.contains('TICKETING DATABASE ERROR')){
            return
        }
        warn("error 2 ${it}: ${e.message}")
        return
    }
    def reportData = data["DAILY_SALES_REPORT_ITEMS"];

    def ticketPcc = ''
    if (it.gdsAccount != null) {
        def gdsAcctEntity = it.gdsAccount.getEntity()
        if (gdsAcctEntity != null) {
            ticketPcc = gdsAcctEntity.getPrimaryPCC()
        }
    }

    def pcc2 = it.pcc

    warn 'reportData: ' + reportData
    reportData.each{
        if (it.conjCount > 0) {
            int conjLength = String.valueOf(it.conjCount).length() + 1//кол-во разрядов+1 для кооректной записи в amadeusReportData
            String start = it.ticketNumber.substring(0, it.ticketNumber.length() - conjLength)
            String end = it.ticketNumber.substring(it.ticketNumber.length() - conjLength)
            for (int i = 0; i <= it.conjCount; i++) {
                amadeusReportData[start + (Integer.valueOf(end) + i)] = it
                pccByTicketNumber[start + (Integer.valueOf(end) + i)] = pcc2 + '/' + ticketPcc
            }
        } else {
            amadeusReportData[it.ticketNumber] = it
            pccByTicketNumber[it.ticketNumber] = pcc2 + '/' + ticketPcc
        }
    }
}

text('Сверка продаж BSP в ГДС AMADEUS за ' + reportDate, 'title')
2.times{nextRow()}

bookingFilesWithNoTicketNumbers.each{
    text('В заказе '+it+' присутствуют билеты без номера', 'error', 5, 1)
    nextRow()
}

text("Номер заказа", "header")
columnWidth(35)

nextColumn()
text('Номер билета', 'header')
columnWidth(35)

nextColumn()
text('Пассажир', 'header')
columnWidth(35)
nextColumn()
text('ГДС', 'header')
nextColumn()
text('МОМ', 'header')
nextColumn()

text('PCC', 'header')
nextColumn()

warn 'momData.keys (before gdsIter): '  + momData.keySet()

def gdsIter=amadeusReportData.iterator()

while(gdsIter.hasNext()){
    def entry = gdsIter.next()
    gdsIter.remove()
    def ticketNumber = entry.key;
    def ticket = entry.value;


    boolean isGdsTicketVoided = false
    try {
        isGdsTicketVoided = ticket.status == ProductStatus.VOID
        if (isGdsTicketVoided) {
            warn 'ticket voided: ' + ticketNumber
        } else {
            warn 'ticket not voided: ' + ticketNumber + ', ticket.status: ' + ticket.status
        }
    } catch (Exception e) {
        warn("error 3: ${e.message}")
    }

    if (isGdsTicketVoided) {
        warn 'voided ticket: ' + ticketNumber
        momVoidedData.remove(ticketNumber)
        continue
    }

    def momItem = momData.remove ticketNumber
    def error = momItem ? false : true
    def fmt = error ? 'error' : 'textData'

    info 'Processing PCC ' + pccByTicketNumber[ticketNumber]

    def pccTxt = pccByTicketNumber[ticketNumber] ?: ''

    warn 'gdsIter, processing ticket ' + ticketNumber

    if (ticketNumber.contains('2482854147')) {
        warn 'pccTxt: ' + pccTxt
    }



    def curPccs = []
    if (pccTxt.contains('/')) {
        def parts = pccTxt.split('/')
        curPccs.add(parts[0])
        curPccs.add(parts[1])
    } else {
        curPccs.add(pccTxt)
    }

    if (!relevantPccs.intersect(curPccs).isEmpty() || relevantPccs.isEmpty()) {
        nextRow()

        text(momItem?.bookingNumber, fmt)
        nextColumn()

        text(ticketNumber, fmt)
        nextColumn()
        text(ticket.passenger, fmt)
        nextColumn()
        text('X', fmt)
        nextColumn()
        text(momItem? 'X' : ' ', fmt)
        nextColumn()
        text(pccByTicketNumber[ticketNumber], 'textData')
    }
}

//VIP-4952
def isNotAdult = { product->
    PassengerTypeValue passagerTypeValue = DictHelper.getPassengerTypeValue(product.passengerType)
    return (passagerTypeValue == PassengerTypeValue.CHILD) || (passagerTypeValue == PassengerTypeValue.INFANT)|| (passagerTypeValue == PassengerTypeValue.INFANT_WITH_SITE);
}

def gender={ product->
    def passengerGender =
            product?.getTraveller()?.getPassport()?.getGender();
    boolean isMale = (passengerGender == Gender.MALE);
    boolean isChild = isNotAdult(product);

    String genderStr = "";
    if (isMale) {
        if (isChild) {
            genderStr = "MSTR";
        } else {
            genderStr = "MR";
        }
    } else {
        if (isChild) {
            genderStr = "MISS";
        } else {
            genderStr = "MRS";
        }
    }
    return genderStr;
}

def notFoundMomDataClosure = { Map.Entry it ->
    def ticketNumber = it.key;
    def ticket = it.value;
    def product =
            BookingHelper.findProductByUid(
                    ticket.getNavigationKey(),
                    es.resolve(ticket.getSource()).getEntity());

    def pccToLookFor = product.getPcc()
    /*
    if (pccToLookFor == "B80F") {
        pccToLookFor = "9HUH"
    }
    */
    warn 'ticket, notFoundMomDataClosure: ' + it.key + ', PCC. ' + pccToLookFor

    if (relevantPccs.contains(pccToLookFor) || relevantPccs.isEmpty()) {
        warn 'notFoundMomDataClosure, product.getClass(): ' + product.getClass()

        if (ticketNumber.contains("2482854147")) {
            warn 'notFoundMomDataClosure(2482854147), ticket: ' + ticket + ', product.getClass(): ' + product.getClass()
        }

        nextRow()
        text(it.value.bookingNumber, 'error')
        nextColumn()
        text(ticketNumber, 'error')
        nextColumn()
        def lname = product?.getTraveller()?.getPassport()?.getLastName();
        def fname = product?.getTraveller()?.getPassport()?.getFirstName();
        def nameBuilder =
                new StringBuilder(lname ? lname : '').append('/')
                        .append(fname ? fname : '')
                        .append(' ').append(gender(product))
        text(nameBuilder.toString().toUpperCase(), 'error');
        nextColumn()
        text(' ', 'error')
        nextColumn()
        text('X', 'error')
        nextColumn()
        text(pccToLookFor, 'error')
    }
}

warn 'momData.keys (before notFoundMomDataClosure): '  + momData.keySet()
momData.each(notFoundMomDataClosure)
momVoidedData.each(notFoundMomDataClosure)
