import com.gridnine.xtrip.common.model.booking.AeroexpressTicketIndex
import com.gridnine.xtrip.common.model.booking.ProductStatus
import com.gridnine.xtrip.common.model.EntityReference
import com.gridnine.xtrip.common.model.EntityContainer
import com.gridnine.xtrip.common.model.profile.Organization
import com.gridnine.xtrip.common.model.entity.EntityStorage
import com.gridnine.xtrip.common.l10n.model.L10nString
import com.gridnine.xtrip.common.l10n.model.L10nStringHelper
import com.gridnine.xtrip.common.util.LocaleUtil
import com.gridnine.xtrip.common.util.MiscUtil
import com.gridnine.xtrip.common.model.dict.AddressType
import com.gridnine.xtrip.common.model.profile.Address
import java.util.Date
import com.gridnine.xtrip.common.model.entity.EntityStorage
import com.gridnine.xtrip.common.model.booking.BookingFile
import com.gridnine.xtrip.common.model.booking.AeroexpressTicket
import com.gridnine.xtrip.common.model.booking.Reservation
import com.gridnine.xtrip.common.model.booking.BaseProduct
import java.text.SimpleDateFormat
import com.gridnine.xtrip.common.model.helpers.ProfileHelper

import groovy.transform.Field


createStyle(name: "head", h_alignment: "RIGHT")
createStyle(name: "title", h_alignment: "CENTER", fontBold : true)
createStyle(name: "tableName", h_alignment: "LEFT")
createStyle(name: "header", h_alignment: "CENTER", v_alignment: "CENTER", fontBold : true, leftBorder:'THIN', rightBorder:'THIN', topBorder:'THIN', bottomBorder:'THIN', wrapText: true)
createStyle(name: 'textData', h_alignment: 'CENTER', v_alignment: 'CENTER', leftBorder:'THIN', rightBorder:'THIN', topBorder:'THIN', bottomBorder:'THIN')
createStyle(name: 'numberData', parent: 'textData', h_alignment: 'RIGHT')
createStyle(name: 'total', fontBold: true,  h_alignment: 'LEFT', v_alignment: 'CENTER', leftBorder:'THIN', rightBorder:'THIN', topBorder:'THIN', bottomBorder:'THIN')
createStyle(name: 'numberTotal', parent: "total", h_alignment: 'RIGHT')


columnCount = 11

def printHead() {
    nextRow()
    text("Приложение №1", "head", columnCount, 1)
    
    nextRow()
    text("к Дополнительному соглашению №___", "head", columnCount, 1)
    
    nextRow()
    text("К Договору № _________________", "head", columnCount, 1)
    
    nextRow()
    text("от \"_____\" ____________ 201__ г.", "head", columnCount, 1)
}

def printTitle() {
    nextRow()
    
    nextRow()
    text("Извещение о продажах Агента _______________", "title", columnCount, 1)

    nextRow()
    text("за период с ___ по ____    _____________2015г.", "title", columnCount, 1)
}

def printSalesTableHeader() {
    nextRow()
    nextRow()
    text("1. Агент осуществил действия по реализации электронных билетов в отчетном периоде в следующем объеме:", "tableName", columnCount, 1)
    
    nextRow()
    nextRow()
    text("Номер электронного билета", "header", 1, 2)
    
    nextColumn()
    text("Дата продажи", "header", 1, 2)
    
    nextColumn()
    text("Дата проезда", "header", 1, 2)
    
    nextColumn()
    text("Дата оплаты", "header", 1, 2)
    
    nextColumn()
    text("№ платежного документа", "header", 1, 2)
    
    nextColumn()
    text("Сумма продажи", "header", 2, 2)
    
    2.times {
        nextColumn()
    }
    text("Наименование контрагента", "header", 1, 2)
    
    nextColumn()
    text("Реквизиты контрагента", "header", 3, 1)
    rowHeight(32, false)
    
    nextRow()
    8.times {
        nextColumn()
    }
    text("ИНН", "header")
    rowHeight(32, false)
    
    nextColumn()
    text("КПП", "header")
    
    nextColumn()
    text("Юридический адрес", "header")
}

def printRefundTableHeader() {
    nextRow()
    nextRow()
    text("2. Агент осуществил действия по возврату электронных билетов, проданных в прошедших отчетных периодах, в следующем объеме:", "tableName", columnCount, 1)
    
    nextRow()
    nextRow()
    text("Номер электронного билета", "header", 1, 2)
    columnWidth(17)
    
    nextColumn()
    text("Дата продажи", "header", 1, 2)
    columnWidth(10)
    
    nextColumn()
    text("Дата проезда", "header", 1, 2)
    columnWidth(10)
    
    nextColumn()
    text("Дата оплаты", "header", 1, 2)
    columnWidth(10)
    
    nextColumn()
    text("№ платежного документа", "header", 1, 2)
    columnWidth(7)
    
    nextColumn()
    text("Дата возврата", "header", 1, 2)
    columnWidth(10)
    
    nextColumn()
    text("Сумма возврата", "header", 1, 2)
    columnWidth(8)
    
    nextColumn()
    text("Наименование контрагента", "header", 1, 2)
    columnWidth(45)
    
    nextColumn()
    text("Реквизиты контрагента", "header", 3, 1)
    rowHeight(32, false)
    
    nextRow()
    8.times {
        nextColumn()
    }
    text("ИНН", "header")
    columnWidth(10)
    rowHeight(32, false)
    
    nextColumn()
    text("КПП", "header")
    columnWidth(10)
    
    nextColumn()
    text("Юридический адрес", "header")
    columnWidth(65)
}

Organization getSubagency(AeroexpressTicketIndex index) {
    if (index.subagency == null) {
        return null
    }
    return EntityStorage.get().resolve(index.subagency)?.entity
}

String getRuString(L10nString str) {
    return L10nStringHelper.getValue(str, LocaleUtil.LOCALE_RU, false)
}

String getOrganizationName(Organization organization) {
    if (organization == null) {
        return null
    }
    if (organization.fullName != null) {
        return getRuString(organization.fullName)
    }
    if (organization.shortName != null) {
        return getRuString(organization.shortName)
    }
    return organization.code
}

String getLegalFormName(Organization organization) {
    String organizationName = getOrganizationName(organization)
    String organizationFormName = organization?.legalForm?.toString(LocaleUtil.LOCALE_RU)
    if (organizationFormName == null || organizationFormName == "") {
        return organizationName
    }
    return "${organizationFormName} \"${organizationName}\""
}

String getLegalAddress(Organization organization) {
    if (organization == null) {
        return null
    }
    Address address = null
    for (Address addr : organization.addresses) {
        if (addr.addressType == AddressType.LEGAL) {
            address = addr
        }
    }
    if (address == null) {
        return null
    }
    return ProfileHelper.buildFullAddress(address, LocaleUtil.LOCALE_RU, false)
} 

def printSellTicket(AeroexpressTicketIndex index) {
    nextRow()
    text(index.ticketNumber, "textData")
    
    nextColumn()
    text(getDateString(index.issueDate), "textData")
    
    nextColumn()
    text(getDateString(index.departureDate), "textData")
    
    nextColumn()
    text(getDateString(index.dateOfVendorPayment), "textData")
    
    nextColumn()
    text("б/н", "textData")
    
    nextColumn()
    number(index.totalSum, "numberData", 2, 1)
    
    Organization subagency = getSubagency(index)
    
    2.times {
        nextColumn()
    }
    text(getLegalFormName(subagency), "textData")
    
    nextColumn()
    text(subagency?.registrationId, "textData")
    
    nextColumn()
    text(subagency?.kpp, "textData")
    
    nextColumn()
    text(getLegalAddress(subagency), "textData")
}

AeroexpressTicket getTicket(AeroexpressTicketIndex index) {
    BookingFile bookingFile = EntityStorage.get().resolve(index.source)?.entity
    if (bookingFile == null) {
        return null;
    }
    for (Reservation reservation : bookingFile.reservations) {
        for (BaseProduct product : reservation.products) {
            if (product instanceof AeroexpressTicket) {
                AeroexpressTicket ticket = product
                if (ticket.getUid() == index.getNavigationKey()) {
                    return ticket
                }
            }
        }
    }
    return null
}

int getIndexVersion(AeroexpressTicketIndex index) {
    try {
        return index.version
    } catch (Exception e) {
        return 0
    }
}

Date getSaleDate(AeroexpressTicketIndex index) {
    if (getIndexVersion(index) > 0) {
        return index.saleDate
    }
    AeroexpressTicket previousTicket = getTicket(index)?.previousProduct
    if (previousTicket == null || previousTicket.status != ProductStatus.SELL) {
        return null
    }
    return previousTicket?.issueDate
}

Date getRefundDate(AeroexpressTicketIndex index) {
    if (getIndexVersion(index) > 0) {
        return index.refundDate
    }
    AeroexpressTicket nextTicket = getTicket(index)?.nextProduct
    if (nextTicket == null || nextTicket.status != ProductStatus.REFUND) {
        return null
    }
    return nextTicket?.issueDate
}

@Field SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy")

String getDateString(Date date) {
    if (date == null) {
        return null
    }
    return dateFormat.format(date)
}

def printRefundTicket(AeroexpressTicketIndex index) {
    nextRow()
    text(index.ticketNumber, "textData")
    
    nextColumn()
    text(getDateString(getSaleDate(index)), "textData")
    
    nextColumn()
    text(getDateString(index.departureDate), "textData")
    
    nextColumn()
    text(getDateString(index.dateOfVendorPayment), "textData")
    
    nextColumn()
    text("б/н", "textData")
    
    nextColumn()
    text(getDateString(index.issueDate), "textData")
    
    nextColumn()
    number(index.totalSum, "numberData")
    
    Organization subagency = getSubagency(index)
    
    nextColumn()
    text(getLegalFormName(subagency), "textData")
    
    nextColumn()
    text(subagency.registrationId, "textData")
    
    nextColumn()
    text(subagency.kpp, "textData")
    
    nextColumn()
    text(getLegalAddress(subagency), "textData")
}

def printSalesTotal(Aggregator aggregator) {
    nextRow()
    text("ИТОГО:", "total", 5, 1)
    5.times {
        nextColumn()
    }
    number(aggregator.totalSum, "numberTotal", 2, 1)
    2.times {
        nextColumn()
    }
    text("", "total", 4, 1)
}

def printRefundTotal(Aggregator aggregator) {
    nextRow()
    text("ИТОГО:", "total", 6, 1)
    6.times {
        nextColumn()
    }
    number(aggregator.totalSum, "numberTotal")
    nextColumn()
    text("", "total", 4, 1)
}

class Aggregator {
    BigDecimal totalSum = BigDecimal.ZERO
    
    void append(AeroexpressTicketIndex index) {
        this.totalSum = MiscUtil.sum(this.totalSum, index.totalSum)
    }
}

boolean isSameMonth(Date date1, Date date2) {
    if (date1 == null || date2 == null) {
        return null
    }
    return date1.month == date2.month
}

///////////////////////////////////////////////

Aggregator aggregator = new Aggregator()
boolean isRefund = false

printHead()
printTitle()
printSalesTableHeader()

tickets { AeroexpressTicketIndex index ->
    if (index.status == ProductStatus.SELL) {
        Date saleDate = index.issueDate
        Date refundDate = getRefundDate(index)
        if (isSameMonth(saleDate, refundDate)) {
            return
        }
        printSellTicket(index)
    } else if (index.status == ProductStatus.REFUND) {
        if (!isRefund) {
            printSalesTotal(aggregator)
            aggregator = new Aggregator()
            printRefundTableHeader()
            isRefund = true
        }
        Date saleDate = getSaleDate(index)
        Date refundDate = index.issueDate
        if (isSameMonth(saleDate, refundDate)) {
            return
        }
        printRefundTicket(index)
    }
    aggregator.append(index)
}

if (!isRefund) {
    printSalesTotal(aggregator)
    printRefundTableHeader()
    aggregator = new Aggregator()
}

printRefundTotal(aggregator)