import com.gridnine.xtrip.common.l10n.model.L10nStringHelper
import com.gridnine.xtrip.common.l10n.model.LocaleHelper
import com.gridnine.xtrip.common.l10n.model.PersonalLocalizableNameUtil
import com.gridnine.xtrip.common.model.EntityContainer
import com.gridnine.xtrip.common.model.EntityReference
import com.gridnine.xtrip.common.model.booking.AeroexpressTicket
import com.gridnine.xtrip.common.model.booking.FinanceDocumentType
import com.gridnine.xtrip.common.model.booking.MCOFees
import com.gridnine.xtrip.common.model.booking.ProductStatus
import com.gridnine.xtrip.common.model.booking.additionalservice.AdditionalServiceProduct
import com.gridnine.xtrip.common.model.booking.agencymemo.AgencyMemoProduct
import com.gridnine.xtrip.common.model.booking.air.Product
import com.gridnine.xtrip.common.model.booking.carrental.CarRentalProduct
import com.gridnine.xtrip.common.model.booking.commission.ProductType
import com.gridnine.xtrip.common.model.booking.insurance.InsuranceAccident
import com.gridnine.xtrip.common.model.booking.insurance.InsuranceTouristic
import com.gridnine.xtrip.common.model.booking.misc.AgentTouch
import com.gridnine.xtrip.common.model.booking.misc.UniversalProduct
import com.gridnine.xtrip.common.model.booking.railway.*
import com.gridnine.xtrip.common.model.booking.taxi.TaxiProduct
import com.gridnine.xtrip.common.model.booking.transfers.Transfer
import com.gridnine.xtrip.common.model.booking.visa.VisaProduct
import com.gridnine.xtrip.common.model.booking.xtriphotels.HotelProduct
import com.gridnine.xtrip.common.model.delivery.Delivery
import com.gridnine.xtrip.common.model.dict.ClassOfService
import com.gridnine.xtrip.common.model.entity.EntityStorage
import com.gridnine.xtrip.common.model.entity.EntityStorageContext
import com.gridnine.xtrip.common.model.entity.EntityStorageHelper
import com.gridnine.xtrip.common.model.finance.Shipment
import com.gridnine.xtrip.common.model.helpers.AirProductHelper
import com.gridnine.xtrip.common.model.helpers.DictHelper
import com.gridnine.xtrip.common.model.helpers.GeneralProductHelper
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.util.TextUtil
import com.gridnine.xtrip.server.model.helpers.BillingItemHelper
import com.gridnine.xtrip.server.model.ibus.finance.documents.FinanceDocumentsIbusHelper

import java.math.RoundingMode
import java.util.regex.Matcher
import java.util.regex.Pattern

def dateFormat = "dd.MM.yyyy HH:mm:ss"

xml.pi("xml": ["version": "1.0", "encoding": "utf-8"])
xml.Document() {
    EntityStorageContext context = new EntityStorageContext()
    ship = (Shipment) shipment
    NumDoc(ship.getNumber())
    DateDoc(ship.getDate() ? ship.getDate().format(dateFormat) : null)
    EntityReference<Contract> contractRef = FinanceDocumentsIbusHelper.createContractReference(ship.getContract())
    if (contractRef != null) {
        EntityContainer<Contract> contract = EntityStorageHelper.resolve(contractRef, context)
        if (contract != null) {
            NumContract(contract.getEntity().getNumber())
            if (contract.getEntity().getStartDate() != null) {
                DateContract(contract.getEntity().getStartDate().format(dateFormat))
            } else {
                DateContract()
            }
        } else {
            NumContract()
            DateContract()
        }
    } else {
        NumContract()
        DateContract()
    }
    (ship.getBillingItems()).each { billingItem ->
        strTip = null
        refund = null
        strNumDoc = null
        strNumDate = null
        requestFam = null
        dateOfDeparture = null
        service = null
        fio = null
        airlines = null
        inn = null
        classTicket = null
        linerary = null
        amount = "0,00"
        taxes = "0,00"
        stNDS = "0,00"
        amountNDS = "0,00"
        amountWithoutNDS = "0,00"
        amountWithNDS = "0,00"

        item = EntityStorageHelper.resolve(billingItem, context)
        if (item != null) {
            service = item.getName()
            fio = BillingItemHelper.getTravellerName(item)
            itemAmount = item.getAmount()
            if (itemAmount != null) {
                if (itemAmount.getTotal() != null) {
                    amountWithNDS = itemAmount.getTotal()
                    if (BillingItemHelper.isTax(item)) {
                        taxes = itemAmount.getTotal()
                    } else {
                        amount = itemAmount.getTotal()
                    }
                }
                amountWithoutNDS = itemAmount.getValue()
                stNDS = itemAmount.getVat() ? itemAmount.getVat() + "%" : "0,00"
                amountNDS = itemAmount.getVatAmount()
            }
            if (BillingItemHelper.isFee(item)) {
                strTip = "Сервисный сбор"
                strNumDoc = ship.getNumber()
                strNumDate = ship.getDate() ? ship.getDate().format(dateFormat) : null
                airlines = "ТТ-Трэвел"
                inn = "7714775020/771401001"
            }
            product = EntityStorageHelper.resolve(item.getProduct(), context)
            if (product != null) {
                handler = GeneralProductHelper.getHandler(product)
                refund = handler.getStatus(product).equals(ProductStatus.REFUND) ? "1" : "0"
                linerary = handler.getLocalizedRouteLine(product)
                requestFam = getPersonName(product.getReservation().getBookingAgent())
                if (!BillingItemHelper.isFee(item)) {
                    refOrganization = (EntityReference<Organization>) product.getValue("supplier")
                    if (refOrganization != null) {
                        airlines = refOrganization.getCaption()
                        organization = EntityStorageHelper.resolve(refOrganization, context)
                        if (organization != null) {
                            if (!TextUtil.isBlank(organization.getEntity().getRegistrationId())) {
                                if (TextUtil.isBlank(organization.getEntity().getKpp())) {
                                    inn = organization.getEntity().getRegistrationId()
                                } else {
                                    inn = organization.getEntity().getRegistrationId() + "/" + organization.getEntity().getKpp()
                                }
                            }
                        }
                    }
                }
                if (product instanceof RailwayProduct) {
                    prod = (RailwayProduct) product
                    if (!BillingItemHelper.isFee(item)) {
                        strTip = ProductType.RAILWAY_PRODUCT.toString()
                        strNumDoc = prod.getSystemNumber()
                        strNumDate = prod.getIssueDate() == null ? null : product.getIssueDate().format(dateFormat)
                        airlines = null
                        inn = null
                        refCarrier = prod.getSegments().get(0).getCarrier()
                        airlines = refCarrier.getCaption()
                        carrier = DictHelper.resolve(refCarrier)
                        if (carrier != null && !TextUtil.isBlank(carrier.getInn())) {
                            if (!TextUtil.isBlank(carrier.getKpp())) {
                                inn = carrier.getInn() + "/" + carrier.getKpp()
                            } else {
                                inn = carrier.getInn()
                            }
                        }
                    }
                    segment = prod.getSegments().get(0)
                    if (segment.getCarriageType() != null) {
                        classTicket = segment.getCarriageType().toString()
                        Matcher matcher = Pattern.compile("[^(]*[(]([^)]+)[)]").matcher(classTicket)
                        if (matcher.matches()) {
                            classTicket = matcher.group(1)
                        }
                    }
                    linerary = handler.getCities(prod, LocaleHelper.getCurrentLocale())
                    dateOfDeparture = prod.getSegments().get(0).getDepartureDate().format(dateFormat)
                } else if (product instanceof Product) {
                    prod = (Product) product
                    if (!BillingItemHelper.isFee(item)) {
                        strTip = ProductType.AIR_TICKET.toString()
                        strNumDoc = prod.getSystemNumber()
                        strNumDate = prod.getIssueDate() == null ? null : product.getIssueDate().format(dateFormat)
                        airlines = null
                        inn = null
                        refCarrier = prod.getCarrier()
                        airlines = refCarrier.getCaption()
                        carrier = DictHelper.resolve(refCarrier)
                        if (carrier != null && !TextUtil.isBlank(carrier.getRegistrationId())) {
                            if (!TextUtil.isBlank(carrier.getKpp())) {
                                inn = carrier.getRegistrationId() + "/" + carrier.getKpp()
                            } else {
                                inn = carrier.getRegistrationId()
                            }
                        }
                    }
                    classesOfService = AirProductHelper.getSegments(prod.getSegmentTariffs()).collect { it.getServiceClass() }
                    if (classesOfService.contains(ClassOfService.PREMIUM_FIRST)) {
                        classTicket = ClassOfService.PREMIUM_FIRST.toString()
                    } else if (classesOfService.contains(ClassOfService.FIRST)) {
                        classTicket = ClassOfService.FIRST.toString()
                    } else if (classesOfService.contains(ClassOfService.PREMIUM_BUSINESS)) {
                        classTicket = ClassOfService.PREMIUM_BUSINESS.toString()
                    } else if (classesOfService.contains(ClassOfService.BUSINESS)) {
                        classTicket = ClassOfService.BUSINESS.toString()
                    } else if (classesOfService.contains(ClassOfService.PREMIUM)) {
                        classTicket = ClassOfService.PREMIUM.toString()
                    } else {
                        classTicket = ClassOfService.ECONOMY.toString()
                    }
                    dateOfDeparture = prod.getSegmentTariffs().get(0).getSegments().get(0).getStartDate().format(dateFormat)
                } else if (product instanceof HotelProduct) {
                    prod = (HotelProduct) product
                    if (!BillingItemHelper.isFee(item)) {
                        strTip = ProductType.HOTEL_RESERVATION.toString()
                        vfd = prod.getVendorFinanceDocumentsData()
                        if (vfd != null) {
                            inv = vfd.find { it.getType().equals(FinanceDocumentType.INVOICE_FACTURA) }
                            if (inv != null) {
                                strNumDoc = inv.getNumber()
                                strNumDate = inv.getDate() == null ? null : inv.getDate().format(dateFormat)
                            }
                        }
                        if (itemAmount != null && prod.getRoomCount() != null) {
                            amount = itemAmount.getValue().divide(BigDecimal.valueOf(prod.getRoomCount()), 2, RoundingMode.HALF_UP)
                        }
                    }
                    classTicket = prod.getRooms().get(0).getRoomName()
                    dateOfDeparture = handler.findLastTravelDate(prod).format(dateFormat)
                } else if (product instanceof VisaProduct) {
                    prod = (VisaProduct) product
                    if (!BillingItemHelper.isFee(item)) {
                        strTip = ProductType.VISA_PRODUCT.toString()
                    }
                    dateOfDeparture = prod.getEndDate().format(dateFormat)
                } else if (product instanceof AeroexpressTicket) {
                    prod = (AeroexpressTicket) product
                    if (!BillingItemHelper.isFee(item)) {
                        strTip = ProductType.AEROEXPRESS
                    }
                    classTicket = prod.getClassOfService().toString()
                    dateOfDeparture = prod.getDepartureDate().format(dateFormat)
                } else if (!BillingItemHelper.isFee(item)) {
                    if (product instanceof RailwayReferenceMCO) {
                        strTip = ProductType.RAILWAY_REFERENCE_MCO
                    } else if (product instanceof RailwayCrimeaMco) {
                        strTip = ProductType.RAILWAY_CRIMEA_MCO
                    } else if (product instanceof InsuranceTouristic) {
                        strTip = ProductType.INSURANCE_TOURISTIC
                    } else if (product instanceof InsuranceAccident) {
                        strTip = ProductType.INSURANCE_ACCIDENT
                    } else if (product instanceof CarRentalProduct) {
                        strTip = ProductType.CAR_RENTAL
                    } else if (product instanceof Delivery) {
                        strTip = ProductType.DELIVERY
                    } else if (product instanceof Transfer) {
                        strTip = ProductType.TRANSFER
                    } else if (product instanceof UniversalProduct) {
                        strTip = ProductType.MISC_PRODUCT
                    } else if (product instanceof MCOFees) {
                        strTip = ProductType.MCO_FEES
                    } else if (product instanceof AgencyMemoProduct) {
                        strTip = ProductType.AGENCY_MEMO_PRODUCT
                    } else if (product instanceof AgentTouch) {
                        strTip = ProductType.AGENT_TOUCH
                    } else if (product instanceof AdditionalServiceProduct) {
                        strTip = ProductType.ADDITIONAL_SERVICE
                    } else if (product instanceof TaxiProduct) {
                        strTip = ProductType.TAXI
                    } else if (product instanceof RailwayMcoProduct) {
                        strTip = ProductType.RAILWAY_MCO
                    }
                }
            }

            StrDoc() {
                StrTip(strTip)
                Refund(refund)
                StrNumDoc(strNumDoc)
                StrNumDate(strNumDate)
                RequestFam(requestFam)
                DateOfDeparture(dateOfDeparture)
                Service(service)
                FIO(fio)
                Airlines(airlines)
                INN(inn)
                ClassTicket(classTicket)
                Linerary(linerary)
                Amount(amount)
                Taxes(taxes)
                StNDS(stNDS)
                AmountNDS(amountNDS)
                AmountWithoutNDS(amountWithoutNDS)
                AmountWithNDS(amountWithNDS)
            }
        }
    }
}

private static String getPersonName(EntityReference<Person> passenger) {
    if (passenger != null) {
        EntityContainer<Person> travellerCtr = EntityStorage.get().resolve(passenger)
        if (travellerCtr == null) {
            return passenger.getCaption()
        }
        String fullName = getFullName(travellerCtr.getEntity(), LocaleHelper.RU_LOCALE, true)
        if (fullName == null) {
            fullName = getFullName(travellerCtr.getEntity(), LocaleHelper.EN_LOCALE, false)
        }
        if (fullName == null) {
            return passenger.getCaption()
        }
        return fullName
    } else {
        return ""
    }
}

private static String getFullName(final Person person, final Locale locale, final boolean strict) {
    if (person == null) {
        return null;
    }
    String lastName = L10nStringHelper.getValue(person.getLastName(), locale, strict);
    String firstName = L10nStringHelper.getValue(person.getFirstName(), locale, strict);
    String middleName = L10nStringHelper.getValue(person.getMiddleName(), locale, strict);

    if (TextUtil.isBlank(lastName) && TextUtil.isBlank(firstName) && TextUtil.isBlank(middleName)) {
        return null
    }
    return PersonalLocalizableNameUtil.buildFullName(person, false, locale, strict);
}