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

import com.gridnine.xtrip.common.l10n.model.LocaleHelper
import com.gridnine.xtrip.common.model.booking.BaseProduct
import com.gridnine.xtrip.common.model.booking.CommonProductIndex
import com.gridnine.xtrip.common.model.booking.GeneralProductFop;
import com.gridnine.xtrip.common.model.booking.ProductStatus
import com.gridnine.xtrip.common.model.booking.Traveller;
import com.gridnine.xtrip.common.model.booking.air.Product
import com.gridnine.xtrip.common.model.booking.insurance.InsuranceAccident
import com.gridnine.xtrip.common.model.booking.insurance.InsuranceAccidentHelper;
import com.gridnine.xtrip.common.model.booking.insurance.InsuranceTouristic
import com.gridnine.xtrip.common.model.booking.insurance.InsuranceTouristicHelper;
import com.gridnine.xtrip.common.model.booking.railway.RailwayProduct
import com.gridnine.xtrip.common.model.dict.ContractType;
import com.gridnine.xtrip.common.model.entity.EntityStorage
import com.gridnine.xtrip.common.model.helpers.BookingHelper
import com.gridnine.xtrip.common.model.helpers.GeneralProductHelper;
import com.gridnine.xtrip.common.model.helpers.ProfileHelper
import com.gridnine.xtrip.common.model.profile.Organization
import com.gridnine.xtrip.common.model.system.VatAmount;
import com.gridnine.xtrip.common.model.entity.parameters.EntityStorageActualizeParameters
import com.gridnine.xtrip.common.model.booking.insurance.InsuranceTripCancel
import com.gridnine.xtrip.common.vip.model.helpers.InsuranceTripCancelHelper

import java.util.Collection
import java.util.ArrayList

import com.gridnine.xtrip.common.model.booking.insurance.InsuranceTripCancelIndex
import com.gridnine.xtrip.common.search.SearchQuery
import com.gridnine.xtrip.common.search.SearchCriterion
import com.gridnine.xtrip.common.util.MiscUtil
import com.gridnine.xtrip.common.util.CollectionUtil
import com.gridnine.xtrip.common.model.EntityReference
import com.gridnine.xtrip.server.vip.b2b.rest.permission.neoport.CriterionHelper
import com.gridnine.xtrip.common.model.booking.archive.ArchivedProductIndex
import com.gridnine.xtrip.common.model.booking.commission.ProductType
import com.gridnine.xtrip.common.model.EntityIndex
import com.gridnine.xtrip.common.vip.model.helpers.InsuranceTripCancelHelper

//CREATING STYLES
createStyle(name: 'title',fontBold: true, h_span: 15, h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight:20)
createStyle(name: 'metadataTitle',fontBold: true, h_span: 2, h_alignment: 'RIGHT', v_alignment: 'CENTER', fontHeight:10)
createStyle(name: 'metadataValue', parent: 'metadataTitle', h_span: 10, fontBold: false, h_alignment: 'LEFT')
createStyle(name: 'metadataDateValue', parent: 'metadataValue', format: 'm/d/yy')
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: 'numberData',parent: 'data',h_alignment: 'RIGHT')
createStyle(name: 'dateData',parent: 'data',h_alignment: 'RIGHT',format: 'm/d/yy')
createStyle(name: 'statusGroupTitle', parent: 'header', h_span: 13, h_alignment: 'RIGHT', fontBold: true)
createStyle(name: 'statusGroupNumber',parent: 'statusGroupTitle',  h_span: 1)
createStyle(name: 'subagencyGroupTitle', parent: 'statusGroupTitle')
createStyle(name: 'subagencyGroupNumber',parent: 'subagencyGroupTitle',  h_span: 1)
createStyle(name: 'totalTitle', parent: 'subagencyGroupTitle')
createStyle(name: 'totalNumber',parent: 'totalTitle', h_span: 1)

//ADDITIONAL FUNCTIONS
def statusName = { EntityIndex it ->
    if(!it.status){
        return 0
    }
    switch (it.status){
        case ProductStatus.SELL:
            return 'Продажа';
        case ProductStatus.VOID:
            return 'Аннулирован';
        case ProductStatus.REFUND:
            return 'Возврат';
        default:
            return '*';
    }
}
def subagentCode = {EntityStorage.get().resolve(it.subagency)?.getEntity()?.code}
def collToString = {Collection lst ->
    StringBuilder sb = new StringBuilder();
    int idx = 0;
    lst.each {
        if(idx > 0){
            sb.append(',')
        }
        sb.append(it)
        idx++
    }
    return sb.length()>0? sb.toString(): ''
}
def sumFormula = {List lst ->
    StringBuilder sb = new StringBuilder();
    int idx = 0;
    lst.each {
        if(idx > 0){
            sb.append('+')
        }
        sb.append(it)
        idx++
    }
    return sb.length()>0? sb.toString(): '0'
}

def notNull = {BigDecimal it ->
    return it == null? BigDecimal.ZERO: it
}

def insuranceSum = {BaseProduct it ->

    if(it instanceof InsuranceAccident){
        InsuranceAccident ia = it;
        return notNull(ia.insuranceSum?.value)
    }
    if(it instanceof InsuranceTouristic){
        InsuranceTouristic ia = it;
        return notNull(ia.insuranceSum?.value)
    }
    if (it instanceof InsuranceTripCancel) {
        InsuranceTripCancel product = it
        return product.equivalentSum
    }
    return  BigDecimal.ZERO
}

def totalSubagentSum = {EntityIndex idx, BaseProduct product ->
    if (idx instanceof CommonProductIndex) {
        return  notNull(idx.totalSum).add(notNull(idx.subagencyFeeValue))
    }
    
    ProductStatus status = product.status
    if (status == ProductStatus.VOID) {
        return BigDecimal.ZERO
    }
    boolean refund = status == ProductStatus.REFUND || status == ProductStatus.EXCHANGE
    BigDecimal price =BookingHelper.calculateProductPrice(product, ContractType.CLIENT).getTotal()
    BigDecimal commission = BookingHelper.getCommissionValue(GeneralProductHelper.calculateCommissionsEquivalentValue(
       GeneralProductHelper.filterCommissions(
           InsuranceTripCancelHelper.getUnmodifiableCommissions(
               product,ContractType.SUBAGENCY),
           GeneralProductHelper.feePropertyTypes, null,null)),refund)
    return MiscUtil.sum(price, commission)
}
def DocumentType = {BaseProduct it ->
    if(it instanceof InsuranceAccident){
        InsuranceAccident ia = it;
        return BookingHelper.findTraveller(ia.reservation.bookingFile, ia.travellerUid)?.passport?.type?.toString()
    }
    return 'Без документа'
}
def BirthDate = {
    //    if(it instanceof InsuranceAccident){
    //        InsuranceAccident ia = it;
    //        return BookingHelper.findTraveller(ia.reservation.bookingFile, ia.travellerUid)?.birthday
    //    }
    if(it instanceof InsuranceAccident){
        return BookingHelper.findTraveller(it.reservation.bookingFile, it.travellerUid)?.passport?.birthday
    } else if(it instanceof InsuranceTouristic){
        return BookingHelper.findTraveller(it.reservation.bookingFile, it.travellersUids.isEmpty()? null: it.travellersUids.iterator().next())?.birthday
    } else if (it instanceof InsuranceTripCancel) {
        return BookingHelper.findTraveller(it.reservation.bookingFile, it.travellerUid)?.birthday
    }
}
def formpayment = {
    //    BaseProduct it ->
    warn it.getClass().toString()
    try{
        if(it instanceof InsuranceAccident){
            return InsuranceAccidentHelper.getVendorFops(it)[0]?.type?.toString()
        } else if(it instanceof InsuranceTouristic){
            return InsuranceTouristicHelper.getVendorFops(it)[0]?.type?.toString()
        } else if (it instanceof InsuranceTripCancel) {
            return InsuranceTripCancelHelper.getVendorFops(it)[0]?.type?.toString()
        }
    }catch(Exception e){
        warn e.message
    }
    //    return !it.clientFops.isEmpty()? it.clientFops[0]?.type?.toString(): null
    return null
}
def travellerName = {BaseProduct it ->
    if(it instanceof InsuranceAccident){
        InsuranceAccident ia = it;
        return BookingHelper.findTraveller(it.reservation.bookingFile, ia.travellerUid)?.name
    }
    if(it instanceof InsuranceTouristic){
        InsuranceTouristic ia = it;
        return BookingHelper.findTraveller(it.reservation.bookingFile, ia.travellersUids.isEmpty()? null: ia.travellersUids.iterator().next())?.name
    }
    if (it instanceof InsuranceTripCancel) {
        return BookingHelper.findTraveller(it.reservation.bookingFile, it.travellerUid)?.name
    }
    return null;
}
def productTypeIndex = { BaseProduct prod ->
    int productType  = -1;
    if(prod instanceof InsuranceAccident){
        InsuranceAccident ia = prod
        def relatedProduct = BookingHelper.findProductByUid(ia.relatedProductUid, prod.reservation.bookingFile)
        if(relatedProduct instanceof Product){
            return 0
        } else if(relatedProduct instanceof RailwayProduct){
            return 1
        }
        return -1
    } else if (prod instanceof InsuranceTripCancel) {
        return 2
    } else if(prod instanceof InsuranceTouristic){
        return -1
    }
    return -1
}
def Fare = {
    if(it instanceof InsuranceTouristic){
        InsuranceTouristic ia = it;
        if(ia.sport){
            return 'СПОРТ'
        }
        if(ia.business){
            return 'БИЗНЕСС'
        }
        return 'СТАНДАРТ'
    } else if(it instanceof BaseProduct) {
        int productType = productTypeIndex(it)
        switch(productType){
            case 0:
                return 'Общий А/Б'
                break
            case 1:
                return 'Общий Ж/Д'
                break
            case 2:
                return 'Отмена поездки'
            default:
                break
        }
    }
    return null
}
def issuingAgent = {
    def client = EntityStorage.get().resolve(it.client);
    if(!client){
        return ''
    }
    if(client.equals(ProfileHelper.getRetailProfileContainer())){
        def agent =  it.agent
        if(!agent){
            return ''
        }
        EntityStorageActualizeParameters actualizeParameters = new EntityStorageActualizeParameters()
        actualizeParameters.useRemoteCallIfNecessary(true)
        EntityStorage.get().actualize(it.agent, actualizeParameters)
        return it.agent.caption
    }
    return client.getEntity().toString()
}

def reportSubagecies = {
    List subagents = parameters['subagency']
    if(!subagents || subagents.isEmpty()){
        return 'Не указан'
    }
    StringBuilder sb = new StringBuilder();
    int idx = 0;
    subagents.each{
        Organization org = EntityStorage.get().resolve(it)?.getEntity()
        if(org){
            if(idx > 0){
                sb.append(', ')
            }
            sb.append(ProfileHelper.getFullName(org,
                    LocaleHelper.getCurrentLocale(), false))
            idx++
        }
    }
    return sb.length() > 0? sb.toString(): 'Не указан'
}
def ProductType = { BaseProduct prod ->
    int productType = productTypeIndex(prod)
    if(productType == 0){
        return 'Авиа'
    }
    if(productType == 1){
        return 'ЖД'
    }
    if (productType == 2) {
        return 'отмена поездки'
    }
    if(productType == -1){
        return 'Мед'
    }
    return null
}
//additional filterring
List filteredTickets = []
Map bookingsMap = [:]
boolean showMed = Boolean.TRUE.equals(parameters['showMed'])
boolean showAvia = Boolean.TRUE.equals(parameters['showAvia'])
boolean showRailway = Boolean.TRUE.equals(parameters['showRailway'])
boolean showTripCancel = parameters['tripCancel']
boolean hasFiltering = showMed || showAvia || showRailway || showTripCancel

Collection ticketIndexes = new ArrayList()
ticketIndexes.addAll(allTickets)
ticketIndexes.addAll(getTripCancelIndexes())

List getTripCancelIndexes() {
    SearchQuery query = new SearchQuery()
    Date startDate = MiscUtil.clearTime(parameters['params'].periodBegin)
    Date finishDate = MiscUtil.setDayEndTime(parameters['params'].periodEnd)
    query.criteria.criterions.add(SearchCriterion.eq('productType', ProductType.INSURANCE_TRIP_CANCEL))
    query.criteria.criterions.add(SearchCriterion.between('issueDate', startDate, finishDate))
    if (!CollectionUtil.isEmpty(parameters['agents'])) {
        query.criteria.criterions.add(CriterionHelper.getOrEqCriterion('agent', parameters['agents']))
    }
    if (!CollectionUtil.isEmpty(parameters['subagencies'])) {
        query.criteria.criterions.add(CriterionHelper.getOrEqCriterion('subagency', parameters['subagencies']))
    }
    if (!CollectionUtil.isEmpty(parameters['AGENCY'])) {
        query.criteria.criterions.add(CriterionHelper.getOrEqCriterion('agency', parameters['AGENCY']))
    }
    return EntityStorage.get().search(ArchivedProductIndex.class, query).data
}

ticketIndexes.each{EntityIndex idx ->
    def bookingCtr = EntityStorage.get().resolve(idx.source)
    if(!bookingCtr){
        return;
    }
    def prod = BookingHelper.findProductByUid(idx.navigationKey, bookingCtr.entity)
    if(!prod){
        return
    }
    int productType  = -1;
    if(prod instanceof InsuranceAccident){
        InsuranceAccident ia = prod
        def relatedProduct = BookingHelper.findProductByUid(ia.relatedProductUid, bookingCtr.entity)
        if(relatedProduct instanceof Product){
            productType = 0
        } else if(relatedProduct instanceof RailwayProduct){
            productType = 1
        } else{
            productType = 2
        }
    } else if(prod instanceof InsuranceTouristic){
        productType = 2
    } else if (prod instanceof InsuranceTripCancel) {
        productType = 3
    }
    boolean match = !hasFiltering;
    switch (productType){
        case 0:
            match = !hasFiltering || showAvia
            break;
        case 1:
            match = !hasFiltering || showRailway
            break;
        case 2:
            match = !hasFiltering || showMed
            break;
        case 3:
            match = !hasFiltering || showTripCancel
        default:
            break;
    }
    if(match){
        filteredTickets << idx
        bookingsMap.put(idx.source, bookingCtr)
    }
}
// sorting
filteredTickets.sort{ a, b ->
    int res = subagentCode(a) <=> subagentCode(b)
    if(res != 0){
        return res
    }
    return - (statusName(a) <=> statusName(b))
}
//REPORT
page{'Страховки'}{

    //title
    rowHeight(30)
    text('Отчет по страховкам ', 'title')
    //metadata
    nextRow();
    rowHeight(13);
    text('Дата составления отчета:', 'metadataTitle');
    nextColumn();date(new Date(), 'metadataDateValue');
    nextRow();
    text('Период:', 'metadataTitle');
    nextColumn();text(parameters.REPORT_PERIOD, 'metadataValue');
    nextRow();
    text('Субагент:', 'metadataTitle');
    nextColumn();text(reportSubagecies{}, 'metadataValue');
    int scw = 10
    //header
    2.times{nextRow()}
    setStyle('header')
    rowHeight(40)
    columnWidth(2*scw);text('ID полиса');
    nextColumn();columnWidth(3*scw);text('Код Субагента');
    nextColumn();columnWidth(4*scw);text('Выписывающий агент');
    nextColumn();columnWidth(scw);text('№ Полиса');
    nextColumn();columnWidth(scw);text('Статус');
    nextColumn();columnWidth(scw);text('Дата оплаты');
    nextColumn();columnWidth(scw);text('Форма оплаты');
    nextColumn();columnWidth(4*scw);text('ФИО страхователя (пассажира)');
    nextColumn();columnWidth(scw);text('Дата рождения');
    nextColumn();columnWidth(3*scw);text('Вид документа');
    nextColumn();columnWidth(scw);text('Тариф');
    nextColumn();columnWidth(scw);text('№ документа');
    nextColumn();columnWidth(1.5*scw);text('Тип Страховки');
    nextColumn();columnWidth(scw);text('СС, USD');
    nextColumn();columnWidth(scw);text('СП, руб');
    nextColumn(); columnWidth(3 * scw); text("Агентство")
    //data
    List ccRubColumnsSubagents = []
    List cpRubColumnsSubagents = []
    //group by subagent
    groups{subagentCode(it)}{
        //group by status
        List ccRubColumnsStatuses = []
        List cpRubColumnsStatuses = []
        groups{statusName(it)}{
            String ccRubColumn = cellIndex(1,-1)
            String cpRubColumn = cellIndex(1,0)
            filteredTickets.each{EntityIndex idx ->
                def bookingCtr = bookingsMap[idx.source]
                if(!bookingCtr){
                    return;
                }
                def ticket = BookingHelper.findProductByUid(idx.navigationKey, bookingCtr.entity)
                nextRow()
                rowHeight(12)
                text(ticket.systemNumber, 'textData');
                nextColumn();text(subagentCode(idx), 'textData');
                nextColumn();text(issuingAgent(idx), 'textData');
                nextColumn();text(ticket.systemNumber, 'textData');
                nextColumn();text(statusName(idx), 'textData');
                nextColumn();date(idx.issueDate, 'dateData');
                nextColumn();
                
                text(formpayment(ticket), 'textData');
                nextColumn();text(travellerName(ticket), 'textData');
                nextColumn();date(BirthDate(ticket), 'dateData');
                nextColumn();text(DocumentType(ticket), 'textData');
                nextColumn();text(Fare(ticket), 'textData');
                nextColumn();text(ticket.systemNumber, 'textData');
                nextColumn();text(ProductType(ticket), 'textData');
                nextColumn();number(insuranceSum(ticket), 'numberData');
                nextColumn();number(totalSubagentSum(idx, ticket), 'numberData');
                nextColumn(); text(idx.agency.toString(), 'textData')
            }
            //status group total
            nextRow()
            text('Итого по Статусу','statusGroupTitle')
            nextColumn();formula("SUM(${ccRubColumn}:${cellIndex(-1,0)})",'statusGroupNumber')
            ccRubColumnsStatuses << cellIndex(0,0)
            nextColumn();formula("SUM(${cpRubColumn}:${cellIndex(-1,0)})",'statusGroupNumber')
            cpRubColumnsStatuses << cellIndex(0,0)
        }
        //subagent group total
        nextRow()
        text('Итого по субагенту','subagencyGroupTitle')
        nextColumn();formula(sumFormula(ccRubColumnsStatuses),'subagencyGroupNumber');
        ccRubColumnsSubagents << cellIndex(0,0);
        nextColumn();formula(sumFormula(cpRubColumnsStatuses),'subagencyGroupNumber');
        cpRubColumnsSubagents << cellIndex(0,0);
    }
    nextRow()
    text('Итого по продажам','totalTitle')
    nextColumn();formula(sumFormula(ccRubColumnsSubagents),'totalNumber')
    nextColumn();formula(sumFormula(cpRubColumnsSubagents),'totalNumber')
}
