import com.gridnine.xtrip.common.model.EntityContainer
import com.gridnine.xtrip.common.model.EntityReference
import com.gridnine.xtrip.common.model.dict.ContractType
import com.gridnine.xtrip.common.model.entity.EntityStorage
import com.gridnine.xtrip.common.model.entity.parameters.EntityStorageSaveParameters
import com.gridnine.xtrip.common.model.profile.Contract
import com.gridnine.xtrip.common.model.profile.ContractCustomerInfo
import com.gridnine.xtrip.common.model.profile.Organization
import com.gridnine.xtrip.common.model.profile.OrganizationIndex
import com.gridnine.xtrip.common.model.profile.OrganizationType
import com.gridnine.xtrip.common.model.system.*
import com.gridnine.xtrip.common.search.SearchCriterion
import com.gridnine.xtrip.common.search.SearchQuery
import com.gridnine.xtrip.common.search.SearchResult
import com.gridnine.xtrip.common.vip.ProfileHelper
import com.gridnine.xtrip.server.model.tasks.standard.MassCreatingTransactionsTask
import org.apache.poi.hssf.usermodel.HSSFWorkbook
import org.apache.poi.poifs.filesystem.POIFSFileSystem
import org.apache.poi.ss.usermodel.Cell
import org.apache.poi.ss.usermodel.Workbook
import org.apache.poi.xssf.usermodel.XSSFWorkbook

message("Start script - mass creating transactions - TIN variant")
process()

void process() {

    MassCreatingTransactionsTask.InputFile file = inputFile;
    if (file == null) {
        message("no file");
        return;
    }
    InputStream inputStream = new ByteArrayInputStream(file.getBody());
    Workbook workbook = null;
    if (file.getName().endsWith(".xlsx")) {
        //excel 2007
        workbook = new XSSFWorkbook(inputStream);
    } else if (file.getName().endsWith(".xls")) {
        //excel 2003
        POIFSFileSystem fs = new POIFSFileSystem(inputStream);
        workbook = new HSSFWorkbook(fs);
    }
    if (workbook == null) {
        message("no excel extension file=" + file.getName());
        return;
    }
    if (workbook.getNumberOfSheets() == 0) {
        message("can't handle workbook, no sheets");
        return;
    }

    Iterator<org.apache.poi.ss.usermodel.Row> rowIterator = workbook.getSheetAt(0).rowIterator();
    if (!rowIterator.hasNext()) {
        message("can't handle workbook sheet, no rows");
        return;
    }
    rowIterator.next();//miss header

    Set<String> missings = new HashSet<>();

    for (; rowIterator.hasNext(); ) {

        org.apache.poi.ss.usermodel.Row row = rowIterator.next();
        Iterator<Cell> cellIterator = row.cellIterator();

        String agencyCode = readValue(cellIterator);
        String subagencyRegId = readValue(cellIterator);
        Date operationDate = readDateValue(cellIterator);
        String amount = readValue(cellIterator);
        String description = readValue(cellIterator);
        ContractType contractType = null;

        if (agencyCode == "" || subagencyRegId == "" || operationDate == null || amount == "") {
            if (subagencyRegId != "")
                missings.add(subagencyRegId);
            continue;
        }

        // ищем субагентство
        SearchQuery query = new SearchQuery();

        query.getCriteria().getCriterions().add(SearchCriterion.eq(OrganizationIndex.Property.registrationId.name(), subagencyRegId));

        SearchResult<OrganizationIndex> subagencyIndex = EntityStorage.get().search(OrganizationIndex.class, query);

        if (subagencyIndex.getData().size() <= 0) {
            missings.add(subagencyRegId);
            continue;
        }

        EntityReference<Organization> client = subagencyIndex.getData().get(0).getSource();

        EntityContainer<Organization> clientCtr = EntityStorage.get().resolve(client);
        Set<OrganizationType> clientTypes = clientCtr.getEntity().getTypes();

        if (clientTypes.contains(OrganizationType.AGENCY)) {
            contractType = ContractType.SUBAGENCY;
        } else if (clientTypes.contains(OrganizationType.CORPORATE_CLIENT)) {
            contractType = ContractType.CLIENT;
        } else {
            missings.add(subagencyRegId);
            continue;
        }

        // ищем агентство
        query.getCriteria().getCriterions().clear();
        query.getCriteria().getCriterions().add(SearchCriterion.eq(OrganizationIndex.Property.code.name(), agencyCode));

        SearchResult<OrganizationIndex> agencyIndex = EntityStorage.get().search(OrganizationIndex.class, query);

        if (agencyIndex.getData().size() <= 0) {
            missings.add(subagencyRegId);
            continue;
        }

        EntityReference<Organization> agency = agencyIndex.getData().get(0).getSource();

        List<EntityReference<Contract>> foundContracts = ProfileHelper.searchContractsByRelation(agency, client, contractType);
        if (foundContracts.size() <= 0) {
            missings.add(subagencyRegId);
            continue;
        }

        boolean hasStraight = false;
        for (EntityReference<Contract> contract : foundContracts) {
            Contract currentContract = EntityStorage.get().resolve(contract).getEntity();
            if (!currentContract.getPaymentCurrency().equals("RUB") && currentContract.getPaymentCurrency() != null) {
                missings.add(subagencyRegId);
                continue;
            }
            if (currentContract.getCustomer() != null && currentContract.getCustomer().equals(client)) {
                hasStraight = true;
            } else {
                for (ContractCustomerInfo customerInfo : currentContract.getCustomers()) {
                    if (customerInfo.getCustomer().equals(client)) {
                        if (customerInfo.getPaymentCurrency().equals("RUB") || customerInfo.getPaymentCurrency() == null) {
                            hasStraight = true;
                        }
                    }
                }
            }
        }
        if (!hasStraight) {
            missings.add(subagencyRegId);
            continue;
        }

        // парсим сумму
        amount = amount.replace(",", ".");
        BigDecimal moneyValue = new BigDecimal(amount);
        Money amountMoney = new Money();
        amountMoney.setValue(moneyValue);
        amountMoney.setCurrency("RUB");

        // начинаем заполнять транзакцию
        EntityContainer<BillingTransaction> transactionContainer =
            new EntityContainer<>(BillingTransaction.class);
        transactionContainer.getVersionInfo()
            .setDataSource("vip-44331-transaction");

        transactionContainer.getEntity().setClient(client);
        transactionContainer.getEntity().setAgency(agency);
        transactionContainer.getEntity().setContractType(contractType);
        transactionContainer.getEntity().setCategory(BillingTransactionCategory.DEBIT);
        transactionContainer.getEntity().setType(BillingTransactionType.EXPENSE);
        transactionContainer.getEntity().setStatus(BillingTransactionStatus.ACTIVE);
        transactionContainer.getEntity().setSum(amountMoney);
        transactionContainer.getEntity().setPaymentType(PaymentType.INVOICE);
        transactionContainer.getEntity().setDate(operationDate);
        transactionContainer.getEntity().setDescription(description);
        transactionContainer.getEntity().setAutoCreated(false);
        // agent = null
        // order = null

        EntityStorage.get().save(transactionContainer, true, new EntityStorageSaveParameters());

    }

    String missingsString = "";
    Iterator<String> missingsIterator = missings.iterator();
    while (missingsIterator.hasNext()) {
        missingsString += missingsIterator.next() + ";";
    }

    message("Создание транзакций пропущено для организаций с ИНН: " + missingsString);
}

static String readValue(Iterator<Cell> iterator) {

    if (iterator.hasNext()) {

        Cell currentCell = iterator.next();
        if (currentCell.getCellType() != Cell.CELL_TYPE_STRING)
            currentCell.setCellType(Cell.CELL_TYPE_STRING);

        return currentCell.getStringCellValue();

    } else {
        return "";
    }

}

static Date readDateValue(Iterator<Cell> iterator) {

    if (iterator.hasNext()) {

        Cell currentCell = iterator.next();
        return currentCell.getDateCellValue();

    } else {
        return null;
    }

}