import com.gridnine.xtrip.common.model.ClientFop
import com.gridnine.xtrip.common.model.EntityReference
import com.gridnine.xtrip.common.model.booking.GeneralProductCommission
import com.gridnine.xtrip.common.model.booking.ProductStatus
import com.gridnine.xtrip.common.model.booking.air.Commission
import com.gridnine.xtrip.common.model.booking.air.ProductFop
import com.gridnine.xtrip.common.model.booking.air.Segment
import com.gridnine.xtrip.common.model.booking.air.SegmentTariff
import com.gridnine.xtrip.common.model.booking.commission.FeeProperties
import com.gridnine.xtrip.common.model.booking.commission.ReturnCase
import com.gridnine.xtrip.common.model.dict.ClassOfService
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.AirProductTaxHelper
import com.gridnine.xtrip.common.model.helpers.DictHelper
import com.gridnine.xtrip.common.model.helpers.GeneralProductHelper
import com.gridnine.xtrip.common.model.profile.Organization
import com.gridnine.xtrip.common.model.system.PaymentType
import com.gridnine.xtrip.common.model.system.VatAmount
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 com.gridnine.xtrip.common.util.TextUtil

import java.text.SimpleDateFormat

//CREATING STYLES
createStyle(name: 'title', fontBold: true, h_span: 24, h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight: 15)
createStyle(name: 'header', fontBold: true, h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight: 8, leftBorder: 'MEDIUM', rightBorder: 'MEDIUM', topBorder: 'MEDIUM', bottomBorder: 'MEDIUM', wrapText: true)
createStyle(name: 'headerDouble', parent: 'header', h_span: 2)
createStyle(name: 'data', fontBold: false, h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight: 8, leftBorder: 'THIN', rightBorder: 'THIN', topBorder: 'THIN', bottomBorder: 'THIN')
createStyle(name: 'dataLeft', fontBold: false, h_alignment: 'LEFT', v_alignment: 'CENTER', fontHeight: 8, h_span: 2)
createStyle(name: 'textData', parent: 'data')
createStyle(name: 'numberData', parent: 'data', h_alignment: 'RIGHT', format: '#,##0.00')
createStyle(name: 'dateData', parent: 'data', h_alignment: 'RIGHT', format: 'm/d/yy')
createStyle(name: 'totalNumber', h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight: 8, format: '#,##0.00')
createStyle(name: 'sumTitle', h_span: 2, leftBorder: 'THIN', rightBorder: 'THIN', topBorder: 'THIN', bottomBorder: 'THIN', h_alignment: 'LEFT', fontBold: true)
createStyle(name: 'sumNumber', fontBold: true, h_alignment: 'RIGHT', v_alignment: 'CENTER', fontHeight: 8, leftBorder: 'THIN', rightBorder: 'THIN', topBorder: 'THIN', bottomBorder: 'THIN', format: '#,##0.00')


def periodBeginParameter = parameters['key-report-params']?.periodBegin
def periodEndParameter = parameters['key-report-params']?.periodEnd
def agencyName = parameters['key-report-params']?.agency
def agentName = parameters['AGENT']
if (agentName == null)
    agentName = ""
def clients = parameters.get('clients')

if (clients == null || clients.isEmpty()) {
    error("Не задан клиент")
    return
}

def cellFills(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 {
            text(value, style, x, y)
        }
    } else {
        text('', style, x, y)
    }
}

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

def cellFills(Object value) {
    if (value != null) {
        if (value instanceof Number) {
            number(value)
        } else if (value instanceof Date) {
            date(value)
        } else {
            text(value)
        }
    } else {
        text('', style)
    }
}

def isRefoundTicket(BigDecimal value, ProductStatus status) {
    if (!value) {
        return BigDecimal.ZERO
    }
    if (ProductStatus.REFUND == status && value > BigDecimal.ZERO) {
        return MiscUtil.negate(value)
    }
    return value
}

def getTicketTotalFare(AirTicketsTemplateReportTicket ticket) {
    if (ticket.totalFare == null){
        return BigDecimal.ZERO
    }
    if (ProductStatus.REFUND == ticket.status && ticket.totalFare.compareTo(BigDecimal.ZERO) > 0) {
        return MiscUtil.negate(ticket.totalFare)
    }
    if (ticket.isHasPreviousProduct() && ProductStatus.EXCHANGE == ticket.previousProductStatus) {
        return MiscUtil.sub(ticket.totalFare, ticket.previousProductTotalEquivalentFare)
    }
    return ticket.totalFare
}

def getTicketTaxesSum(AirTicketsTemplateReportTicket ticket){
    if (ticket.taxesSum == null){
        return BigDecimal.ZERO
    }
    if (ProductStatus.REFUND == ticket.status && ticket.taxesSum.compareTo(BigDecimal.ZERO) > 0) {
        return MiscUtil.negate(ticket.taxesSum)
    }
    if (ticket.isHasPreviousProduct() && ProductStatus.EXCHANGE == ticket.previousProductStatus) {
        return MiscUtil.sub(ticket.taxesSum, ticket.previousProductTotalEquivalentFare)
    }
    return ticket.taxesSum
}

def getTicketEquivalentFare(AirTicketsTemplateReportTicket ticket){
    if (ticket.equivalentFare == null){
        return BigDecimal.ZERO
    }
    if (ProductStatus.REFUND == ticket.status && ticket.equivalentFare.compareTo(BigDecimal.ZERO) > 0) {
        return MiscUtil.negate(ticket.equivalentFare)
    }
    if (ticket.isHasPreviousProduct() && ProductStatus.EXCHANGE == ticket.previousProductStatus) {
        return MiscUtil.sub(ticket.equivalentFare, ticket.previousProductTotalEquivalentFare)
    }
    return ticket.equivalentFare
}

def absentCorpClient (EntityReference<Organization> corpClient) {
    for (AirTicketsTemplateReportTicket ticket : allTickets) {
        if (ticket.customerProfile == corpClient) {
            return false
        }
    }
    return true
}

def getSdfDate(def date) {
    def sdf = new SimpleDateFormat('dd.MM.yy')
    if (!date){
        return '__________'
    }
    return sdf.format(date)
}

def getSubagentFee(AirTicketsTemplateReportTicket ticket) {
    def subagentFee = BigDecimal.ZERO
    if (ticket.clientFops) {
        for (ClientFop clientFop : ticket.clientFops) {
            if (clientFop.commissions) {
                for (Commission commission : clientFop.commissions) {
                    if (commission?.amount) {
                        FeeProperties properties = EntityStorage.get().resolve(commission.commissionProperties)?.entity as FeeProperties
                        if (ProductStatus.REFUND == ticket.status
                                && (properties?.returnCases?.contains(ReturnCase.REFUND)
                                    || properties?.returnCases?.contains(ReturnCase.FORCED_REFUND))) {
                            subagentFee = subagentFee.add(MiscUtil.negate(MiscUtil.abs(commission.amount.value)))
                        } else {
                            subagentFee = subagentFee.add(MiscUtil.abs(commission.amount.value))
                        }
                    }
                }
            }
        }
    }
    return subagentFee
}

//REPORT
clients.forEach() { EntityReference<Organization> corpClient ->
    Organization org = EntityStorage.get().resolve(corpClient)?.entity
    String clientsShortNames = org?.shortName ?: org?.fullName ?: 'клиент'
    String clientsFullNames = org?.fullName ?: org?.shortName ?: 'клиент'

    def sdf = new SimpleDateFormat('dd.MM.yy')

    if (absentCorpClient(corpClient)) {
        return
    }

    page { clientsShortNames } {
        // Set fix width for amount of sheets
        fitWidth(2)

        // Set portrait mode
        landscape(true)

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

        // Set scale
        scale(70)

        // Set preserve mode
        preserve(false)

        //TITLE
        rowHeight(30)
        cellFills(agencyName?.toString() ?: '__________', 'title')
        nextRow()
        nextRow()
        cellFills("Отчет по авиабилетам, купленным " + clientsFullNames ?: '__________', 'title')
        nextRow()
        nextRow()
        cellFills("За период с " + getSdfDate(periodBeginParameter) + " ПО " + getSdfDate(periodEndParameter), 'title')
        nextRow()
        rowHeight(20)
        cellFills("Составил: ", 'dataLeft'); nextColumn()
        cellFills(agentName?.toString() ?: '__________', 'dataLeft')
        nextRow()
        rowHeight(40)
        columnWidth(7)
        cellFills('#', 'header'); nextColumn()
        columnWidth(9)
        cellFills('А/Билет', 'headerDouble'); nextColumn()
        setStyle('header')
        columnWidth(10)
        cellFills('Дата продажи'); nextColumn()
        columnWidth(15)
        cellFills('Покупатель/контрагент'); nextColumn()
        columnWidth(20)
        cellFills('ФИО'); nextColumn()
        columnWidth(18)
        cellFills('Маршрут'); nextColumn()
        columnWidth(4)
        cellFills('Класс'); nextColumn()
        columnWidth(10)
        cellFills('Дата вылета'); nextColumn()
        columnWidth(10)
        cellFills('Тариф'); nextColumn()
        columnWidth(10)
        cellFills('Коммиссия'); nextColumn()
        columnWidth(10)
        cellFills('Таксы'); nextColumn()
        columnWidth(10)
        cellFills('Штраф'); nextColumn()
        columnWidth(10)
        cellFills('НДС'); nextColumn()
        columnWidth(10)
        cellFills('Стоимость билета'); nextColumn()
        columnWidth(10)
        cellFills('Сборы'); nextColumn()
        columnWidth(10)
        cellFills('НДС'); nextColumn()
        columnWidth(10)
        cellFills('Скидка'); nextColumn()
        columnWidth(10)
        cellFills('Всего'); nextColumn()
        columnWidth(24)
        cellFills('Форма оплаты'); nextColumn()

        columnWidth(12)
        cellFills('Дата оплаты'); nextColumn()

        columnWidth(11)
        cellFills('№ счета'); nextColumn()
        columnWidth(11)
        cellFills('№ кред карты'); nextColumn()
        columnWidth(11)
        cellFills('Агент'); nextColumn()
        columnWidth(11)
        cellFills('Класс '); nextColumn()
        columnWidth(13)
        cellFills('Наименование клиента')

        nextRow()
        rowHeight(10)

        //DATA
        def rowNumber = 1
        allTickets.each { AirTicketsTemplateReportTicket ticket ->
            if (ticket.customerProfile != corpClient || ProductStatus.EXCHANGE == ticket.status) {
                return
            }

            cellFills(rowNumber, 'data'); nextColumn()
            columnWidth(5)
            cellFills(ticket.validatingCarrier?.code, 'textData'); nextColumn()
            columnWidth(13)
            cellFills(ticket.ticketNumber, 'textData'); nextColumn()
            date(ticket.issueDate, 'dateData'); nextColumn()
            cellFills(clientsShortNames, 'textData'); nextColumn()
            cellFills(ticket.nameInGDS, 'textData'); nextColumn()
            cellFills(ticket.routeLine, 'textData'); nextColumn()
            String classCode = ""
            for (AirTicketsTemplateReportSegmentTariff st : ticket.segmentTariffs) {
                for (AirTicketsTemplateReportSegment seg : st.segments) {
                    if (TextUtil.isBlank(seg?.fareBasis)) {
                        continue
                    }
                    classCode = seg.fareBasis.trim().substring(0, 1).toUpperCase()
                }
            }
            // класс
            cellFills(classCode, 'textData'); nextColumn()
            // дата вылета
            cellFills(ticket.departureDate, 'dateData'); nextColumn()
            // тариф
            cellFills(getTicketEquivalentFare(ticket), 'numberData'); nextColumn()
            // коммиссия
            cellFills(isRefoundTicket(ticket.vendorCommissionValue, ticket.status), 'numberData'); nextColumn()
            // таксы
            cellFills(getTicketTaxesSum(ticket), 'numberData'); nextColumn()
            // штраф
            cellFills(ticket.penalty ?: BigDecimal.ZERO, 'numberData'); nextColumn()
            BigDecimal tarriffVat = ticket.getTariffEquivalentVat()
            // ндс
            cellFills(tarriffVat ?: BigDecimal.ZERO, 'numberData'); nextColumn()

            BigDecimal subagentFee = getSubagentFee(ticket)

            // стоимость билета
            cellFills(getTicketTotalFare(ticket), 'numberData'); nextColumn()

            // сборы
            cellFills(subagentFee, 'numberData'); nextColumn()

            //НДС от сборов (?)
            EntityReference<Organization> agencyRef = ticket.agency
            Organization agency = null
            if (agencyRef) {
                agency = EntityStorage.get().resolve(agencyRef)?.getEntity()
            }
            BigDecimal feesEquivalentVat = BigDecimal.ZERO
            if (agency && !agency.simpleTaxed) {
                BigDecimal defaulVat = DictHelper.getDefaultVat()
                VatAmount vatAmount = new VatAmount()
                vatAmount.setTotalVat(subagentFee,
                        defaulVat?.doubleValue() ?: 0)
                feesEquivalentVat = vatAmount.getVatAmount()
            }
            // ндс
            cellFills(isRefoundTicket(feesEquivalentVat, ticket.status), 'numberData'); nextColumn()
            def clientDiscount = ticket.clientDiscount
            // скидка
            cellFills(isRefoundTicket(clientDiscount, ticket.status), 'numberData'); nextColumn()
            // всего
            cellFills(isRefoundTicket(subagentFee.add(getTicketTotalFare(ticket)), ticket.status), 'numberData'); nextColumn()
            List<ProductFop> clientFops = ticket.clientProductFops
            PaymentType paymentType = null
            ProductFop productFop = null
            if (clientFops) {
                for (ProductFop prodFop : clientFops) {
                    if (prodFop?.type) {
                        paymentType = prodFop.type
                        paymentDate = prodFop.operationDate
                        productFop = prodFop
                        break
                    }
                }
            }
            cellFills(paymentType?.toString() ?: '', 'textData'); nextColumn()

            if (paymentDate) {
                cellFills(sdf.format(paymentDate).toString(), 'textData')
            } else {
                cellFills(null, 'textData')
            }
            nextColumn()

            cellFills(ticket.settlementAccount, 'textData'); nextColumn()
            cellFills(productFop?.card?.number, 'textData'); nextColumn()
            cellFills(ticket.reservationBookingAgent ?: '', 'textData'); nextColumn()
            ClassOfService classOfService = ticket.classOfService
            cellFills(classOfService?.toString() ?: '', 'textData'); nextColumn()
            cellFills(clientsShortNames, 'textData')
            nextRow()
            rowNumber++
        }

        if (rowNumber > 1) {
            rowHeight(14)
            cellFills('Итого', 'sumTitle')
            7.times {
                nextColumn(); cellFills(null, 'textData')
            }
            cellFills(null, 'textData'); nextColumn()
            8.times { formula("SUM(${cellIndex(-(rowNumber - 1), 0)}:${cellIndex(-1, 0)})", 'sumNumber'); nextColumn() }
            cellFills(null, 'textData'); nextColumn()
            formula("SUM(${cellIndex(-(rowNumber - 1), 0)}:${cellIndex(-1, 0)})", 'sumNumber'); nextColumn()
        }
    }
}