import com.gridnine.xtrip.common.l10n.model.LocaleHelper
import com.gridnine.xtrip.common.model.EntityReference
import com.gridnine.xtrip.common.model.booking.ProductStatus
import com.gridnine.xtrip.common.model.booking.TransportationType
import com.gridnine.xtrip.common.model.dict.ContractType
import com.gridnine.xtrip.common.model.entity.EntityStorage
import com.gridnine.xtrip.common.model.helpers.AirProductHelper
import com.gridnine.xtrip.common.model.helpers.PersonalLocalizableNameFormatter
import com.gridnine.xtrip.common.model.helpers.ProfileHelper
import com.gridnine.xtrip.common.model.profile.Contract
import com.gridnine.xtrip.common.model.profile.Organization
import com.gridnine.xtrip.common.model.profile.Person
import com.gridnine.xtrip.common.reports.model.AirTicketsTemplateReportSegment
import com.gridnine.xtrip.common.reports.model.AirTicketsTemplateReportSegmentTariff
import com.gridnine.xtrip.common.reports.model.AirTicketsTemplateReportTicket
import com.gridnine.xtrip.common.util.MiscUtil

import java.text.SimpleDateFormat

if (parameters['isVatRegistries'] != parameters['vatRegistries']) {
    return
}

// Styles
createStyle(name: 'title', h_alignment: 'CENTER', v_alignment: 'CENTER')
createStyle(name: 'titleH1', fontHeight: 14, parent: 'title')
createStyle(name: 'titleH2', fontHeight: 12, parent: 'title')
createStyle(name: 'titleH3', fontHeight: 9, parent: 'title')
createStyle(name: 'header', h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight: 9)
createStyle(name: 'columnHeader', parent: 'header')
createStyle(name: 'rowHeader', parent: 'header')
createStyle(name: 'data', h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight: 9)
createStyle(name: 'dataText', parent: 'data')
createStyle(name: 'dataText8', parent: 'data', fontHeight: 8)
createStyle(name: 'dataDate', format: 'm/d/yy', parent: 'data')
createStyle(name: 'dataNumber', h_alignment: 'RIGHT', format: '#,##0.00', parent: 'data')
createStyle(name: 'wrap', wrapText: true)
createStyle(name: 'ahl', h_alignment: 'LEFT')
createStyle(name: 'ahc', h_alignment: 'CENTER')
createStyle(name: 'ahr', h_alignment: 'RIGHT')
createStyle(name: 'avt', v_alignment: 'TOP')
createStyle(name: 'avc', v_alignment: 'CENTER')
createStyle(name: 'avb', v_alignment: 'BOTTOM')
createStyle(name: 'aac', h_alignment: 'CENTER', v_alignment: 'CENTER')
createStyle(name: 'bold', fontBold: true)
createStyle(name: 'italic', fontItalic: true)
createStyle(name: 'bt', topBorder: 'THIN')
createStyle(name: 'bl', leftBorder: 'THIN')
createStyle(name: 'bb', bottomBorder: 'THIN')
createStyle(name: 'br', rightBorder: 'THIN')
createStyle(name: 'ba', topBorder: 'THIN', leftBorder: 'THIN', bottomBorder: 'THIN', rightBorder: 'THIN')
createStyle(name: 'green', foreground: 'LIGHT_GREEN')
createStyle(name: 'yellow', foreground: 'YELLOW')
createStyle(name: 'purple', foreground: 'CORAL')
createStyle(name: 'locked', locked: true)

// Properties
Date periodBeginParameter = parameters['key-report-params']?.periodBegin
Date periodEndParameter = parameters['key-report-params']?.periodEnd
EntityReference<Organization> supplierParameter = parameters['key-report-params']?.supplier
EntityReference<Organization> agencyParameter = parameters['key-report-params']?.agency

//Closures
def cellFill(Object value, String style, int x, int y) {
    if (value != null) {
        if (value instanceof Number) {
            number(value, style, x, y)
        } else if (value instanceof Date) {
            date(value, style, x, y)
        } else if (value instanceof Formula){
            formula(value.formula, style, x, y)
        } else {
            text(value, style, x, y)
        }
    } else {
        text('', style, x, y)
    }
}

def cellFill(Object value, String style) {
    if (value != null) {
        if (value instanceof Number) {
            number(value, style)
        } else if (value instanceof Date) {
            date(value, style)
        } else if (value instanceof Formula){
            formula(value.formula, style)
        } else {
            text(value, style)
        }
    } else {
        text('', style)
    }
}

boolean isRouteContainsCIS(final List<AirTicketsTemplateReportSegmentTariff> segmentTariffs) {
    if (segmentTariffs) {
        for (AirTicketsTemplateReportSegmentTariff st : segmentTariffs) {
            for (AirTicketsTemplateReportSegment seg : st.getSegments()) {
                if (AirProductHelper.isCISWithoutDomestic(seg.getDepartureLocation())
                        || AirProductHelper.isCISWithoutDomestic(seg.getArrivalLocation())) {
                    return true
                }
            }
        }
    }
    return false
}

boolean isRouteContainsDVFO(final List<AirTicketsTemplateReportSegmentTariff> segmentTariffs) {
    if (segmentTariffs) {
        for (AirTicketsTemplateReportSegmentTariff st : segmentTariffs) {
            for (AirTicketsTemplateReportSegment seg : st.getSegments()) {
                if (AirProductHelper.isDVFO(seg.getDepartureLocation())
                        || AirProductHelper.isDVFO(seg.getArrivalLocation())) {
                    return true
                }
            }
        }
    }
    return false
}

boolean isRouteContainsKaliningrad(final List<AirTicketsTemplateReportSegmentTariff> segmentTariffs) {
    if (segmentTariffs) {
        for (AirTicketsTemplateReportSegmentTariff st : segmentTariffs) {
            for (AirTicketsTemplateReportSegment seg : st.getSegments()) {
                if (AirProductHelper.isKaliningrad(seg.getDepartureLocation())
                        || AirProductHelper.isKaliningrad(seg.getArrivalLocation())) {
                    return true
                }
            }
        }
    }
    return false
}

boolean isRouteContainCrimea(final List<AirTicketsTemplateReportSegmentTariff> segmentTariffs) {
    if (segmentTariffs) {
        for (AirTicketsTemplateReportSegmentTariff st : segmentTariffs) {
            for (AirTicketsTemplateReportSegment seg : st.getSegments()) {
                if (AirProductHelper.isCrimea(seg.getDepartureLocation())
                        || AirProductHelper.isCrimea(seg.getArrivalLocation())) {
                    return true
                }
            }
        }
    }
    return false
}

def period = {
    def format = new SimpleDateFormat('dd.MM.yyyy')
    return String.format('%s - %s', periodBeginParameter != null ? format.format(periodBeginParameter) : '?', periodEndParameter != null ? format.format(periodEndParameter) : '?')
}

def agencyName = {
    Organization organization = EntityStorage.get().resolve(agencyParameter)?.entity
    return organization ? ProfileHelper.getFullName(organization, LocaleHelper.getLocale('ru', 'RU'), false) : 'Не указано'
}

def contractDate = {
    List<EntityReference<Contract>> contracts = ProfileHelper.getContracts(supplierParameter, supplierParameter, agencyParameter, ContractType.VENDOR, periodBeginParameter, periodEndParameter)
    def contractCustomerInfo = contracts.size() > 0 ? ProfileHelper.getContractCustomerInfo(contracts.get(0), agencyParameter) : null
    def format = new SimpleDateFormat('dd.MM.yyyy')
    return contractCustomerInfo != null && contractCustomerInfo.issueDate != null ? format.format(contractCustomerInfo.issueDate) : '?'
}

def contractNumber = {
    List<EntityReference<Contract>> contracts = ProfileHelper.getContracts(supplierParameter, supplierParameter, agencyParameter, ContractType.VENDOR, periodBeginParameter, periodEndParameter)
    def contractCustomerInfo = contracts.size() > 0 ? ProfileHelper.getContractCustomerInfo(contracts.get(0), agencyParameter) : null
    return contractCustomerInfo ? contractCustomerInfo.number : '?'
}

def ignoreZeroNumber = { BigDecimal number1 ->
    return number1 == BigDecimal.ZERO || number1 == null || number1 == 0 ? '' : number1
}

def directorName = {
    Person person = EntityStorage.get().resolve(requestedParameter('director'))?.entity
    PersonalLocalizableNameFormatter format = new PersonalLocalizableNameFormatter(PersonalLocalizableNameFormatter.SIMPLE)
    return person ? format.format(person, LocaleHelper.getLocale('ru', 'RU'), false) : '?'
}

def responsibleName = {
    Person person = EntityStorage.get().resolve(requestedParameter('responsible'))?.entity
    PersonalLocalizableNameFormatter format = new PersonalLocalizableNameFormatter(PersonalLocalizableNameFormatter.SIMPLE)
    return person ? format.format(person, LocaleHelper.getLocale('ru', 'RU'), false) : '?'
}

def isExchange = { ProductStatus status, BigDecimal num ->
    if (num == null){
        return BigDecimal.ZERO
    }
    return ProductStatus.EXCHANGE == status ? MiscUtil.negate(num) : num
}

def lagguageMvl =  new CalcLagguageData()
def lagguageVvl =  new CalcLagguageData()

def calculate = { AirTicketsTemplateReportTicket ticket , CalcLagguageData cld ->
    if (ticket.equivalentFare != null) {
        cld.totalTariff = cld.totalTariff.add(isExchange(ticket.status, ticket.equivalentFare))
    }
    if ((ticket.vendorCommissionRate != null)
            && (ticket.vendorCommissionValue != null)) {
        cld.totalCommission = cld.totalCommission.add(isExchange(ticket.status, ticket.vendorCommissionValue))
    }
}

def doEstimate = {
    allTickets.each { AirTicketsTemplateReportTicket ticket ->
        if (TransportationType.INTERNATIONAL == ticket.transportationType
        ||  TransportationType.DOMESTIC == ticket.transportationType && isRouteContainsCIS(ticket.segmentTariffs)
        ||  TransportationType.DOMESTIC == ticket.transportationType && isRouteContainCrimea(ticket.segmentTariffs)
        ||  TransportationType.DOMESTIC == ticket.transportationType && isRouteContainsDVFO(ticket.segmentTariffs)
        ||  TransportationType.DOMESTIC == ticket.transportationType && isRouteContainsKaliningrad(ticket.segmentTariffs)) {

            calculate(ticket, lagguageMvl)
        } else if (TransportationType.DOMESTIC == ticket.transportationType) {
            calculate(ticket, lagguageVvl)
        }

    }
}

page{'РП-багаж'} {
    doEstimate()
    // Set fix width for amount of sheets
    fitWidth(1)

    // Set fix height for amount of sheets
    fitHeight(1)

    // Set portrait mode
    landscape(false)

    // Set narrow margins
    margin(0.25, 0.25, 0.25, 0.25)

    // Set scale
    scale(70)

    // Set preserve mode
    preserve(false)

// Report header
    cellFill('РАСЧЕТНОЕ ПИСЬМО ПО ПРОДАЖЕ СВЕРХНОРМАТИВНОГО БАГАЖА', 'titleH2|ahl|bold', 6, 1)
    nextRow()
    cellFill('ДОГОВОР №' + contractNumber() + ' от ' + contractDate() , 'titleH1|ahl|bold', 6, 1)
    nextRow()
    cellFill('АГЕНТ: ' + agencyName(), 'titleH1|ahl|bold', 6, 1)
    nextRow()
    columnWidth(5); nextColumn(); columnWidth(15); nextColumn(); columnWidth(10); nextColumn(); columnWidth(15); nextColumn()
    columnWidth(12); nextColumn(); columnWidth(12)

    nextRow()
    cellFill(period(), 'titleH1|ahc|bold', 6, 1)
    2.times { nextRow() }

// Table 1
    cellFill('1. Выручка', 'columnHeader|ahl', 4, 1)
    nextRow()
    cellFill('Статья', 'columnHeader|ba|ahl', 4, 2);4.times{ nextColumn() }
    cellFill('Итого за месяц', 'columnHeader|ba', 2, 2)
    2.times { nextRow() }
    cellFill('Выручка продажи по ВВЛ', 'dataText|ahl|ba', 4, 1);4.times{ nextColumn() }
    cellFill(ignoreZeroNumber(lagguageVvl.totalTariff), 'dataNumber|ahr|ba', 2, 1)
    nextRow()
    cellFill('Агентское вознаграждение', 'dataText|ahl|ba', 4, 1);4.times{ nextColumn() }
    cellFill(ignoreZeroNumber(lagguageVvl.totalCommission), 'dataNumber|ahr|ba', 2, 1)
    nextRow()
    cellFill('Выручка продажи по МВЛ', 'dataText|ahl|ba', 4, 1);4.times{ nextColumn() }
    cellFill(ignoreZeroNumber(lagguageMvl.totalTariff), 'dataNumber|ahr|ba', 2, 1)
    nextRow()
    cellFill('Агентское вознаграждение', 'dataText|ahl|ba', 4, 1);4.times{ nextColumn() }
    cellFill(ignoreZeroNumber(lagguageMvl.totalCommission), 'dataNumber|ahr|ba', 2, 1)
    nextRow()
    cellFill('Подлежит перечислению Перевозчику', 'columnHeader|ba|ahl', 4, 2);4.times{ nextColumn() }
    cellFill(new Formula("(${cellIndex(-4, 0)}-${cellIndex(-3, 0)})+(${cellIndex(-2, 0)}-${cellIndex(-1, 0)})"), 'dataNumber|ba', 2, 2)
    4.times { nextRow() }

// Table 2
    cellFill('2. Суммы, восстановленные по замечаниям Перевозчика', 'columnHeader|ahl', 4, 1)
    nextRow()
    cellFill('Начеты по претензии', 'columnHeader|ba|ahl', 4, 2);4.times{ nextColumn() }
    cellFill(null, 'columnHeader|ba', 2, 2)
    2.times { nextRow() }
    cellFill('Выплаты', 'dataText|ahl|ba', 4, 1);4.times{ nextColumn() }
    cellFill(null, 'dataNumber|ahr|ba', 2, 1)
    nextRow()
    cellFill('Всего', 'dataText|ahl|ba', 4, 1);4.times{ nextColumn() }
    cellFill(null, 'dataNumber|ahr|ba', 2, 1)
    2.times { nextRow() }
// Table 3
    cellFill('3. Перечисление выручки', 'columnHeader|ahl', 4, 1)
    nextRow()
    cellFill('Фактически перечислено', 'columnHeader|ba|ahl', 4, 2);4.times{ nextColumn() }
    cellFill('Сумма', 'columnHeader|ba', 2, 2)
    2.times { nextRow() }
    cellFill(null, 'dataText|ahl|ba', 4, 1);4.times{ nextColumn() }
    cellFill(null, 'dataNumber|ahr|ba', 2, 1)
    nextRow()
    cellFill(null, 'dataText|ahl|ba', 4, 1);4.times{ nextColumn() }
    cellFill(null, 'dataNumber|ahr|ba', 2, 1)
    nextRow()
    cellFill(null, 'dataText|ahl|ba', 4, 1);4.times{ nextColumn() }
    cellFill(null, 'dataNumber|ahr|ba', 2, 1)
    nextRow()
    cellFill(null, 'dataText|ahl|ba', 4, 1);4.times{ nextColumn() }
    cellFill(null, 'dataNumber|ahr|ba', 2, 1)
    nextRow()
    cellFill(null, 'dataText|ahl|ba', 4, 1);4.times{ nextColumn() }
    cellFill(new Formula("SUM(${cellIndex(-4, 0)}:${cellIndex(-1, 0)})"), 'dataNumber|ba', 2, 1)
    5.times { nextRow() }

// Footer
    cellFill('Руководитель:', 'dataText|ahl', 2, 1)
    2.times { nextColumn() }
    cellFill(directorName(), 'dataText|ahl')
    2.times { nextRow() }
    cellFill('Гл. бухгалтер:', 'dataText|ahl',2 ,1)
    2.times { nextColumn() }
    cellFill(responsibleName(), 'dataText|ahl')
    2.times { nextRow() }
    cellFill('Печать:', 'dataText|ahl', 2, 1)
}

class Formula {
    String formula
    Formula(){}
    Formula(String formula) {
        this.formula = formula
    }

    static Formula getSumFormulaByRow (String start, String end) {
        return new Formula('SUM(' + start + ':' + end + ')')
    }
    static Formula getSumFormulaByCell(String... index) {
        def formula = ''
        for (int i=0; i<index.size(); i++) {
            if(i == 0) {
                formula += index[i]
            } else {
                formula += ',' + index[i]
            }
        }
        return new Formula('SUM(' + formula + ')')
    }
}

class CalcLagguageData {
    BigDecimal totalTariff = BigDecimal.ZERO

    BigDecimal totalCommission = BigDecimal.ZERO

}