package eu.dnetlib.goldoa.service;

import eu.dnetlib.goldoa.domain.*;
import eu.dnetlib.goldoa.service.dao.AlternativeFundingBidDao;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.persistence.criteria.CriteriaBuilder;
import java.io.*;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static eu.dnetlib.goldoa.domain.Constants.*;
import static eu.dnetlib.goldoa.domain.Constants.CONTRACT_PDF;

@Transactional
@Service("alternativeFundingBidManager")
public class AlternativeFundingBidManagerImpl implements AlternativeFundingBidManager {

    @Autowired
    private AlternativeFundingBidDao alternativeFundingBidDao;
    @Autowired
    private InvoiceManager invoiceManager;
    @Autowired
    private OrganizationManager organizationManager;

    @Value("${goldoa.fundingbids}")
    private String fundingbids;

    private Log LOGGER = LogFactory.getLog(RequestManagerImpl.class);

    @PostConstruct
    public void init(){
        LOGGER.debug("Funding bids property: " + fundingbids);
    }
    public void importAlternativeFundingBids(){

        if(Boolean.parseBoolean(fundingbids)){
            String path = "http://195.134.66.230:8380/uploadFiles/";
            BufferedReader br = null;
            String s = "";
            String cvsSplitBy = ",";
            AlternativeFundingBid bid = null;

            try {
                URL url = null;
                URLConnection urlConnection = null;
                try {
                    url = new URL(path + "AlternativeFundingBids-FirstRound.csv");
                    urlConnection = url.openConnection();
                } catch (IOException e) {
                    LOGGER.debug(e);
                }
                br = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
                s = br.readLine();
                while ((s = br.readLine()) != null) {

                    LOGGER.debug("Line -> " + s);

                    String[] line = s.split(cvsSplitBy);
                    String id = !line[0].equals("")?line[0].trim():null;
                    String funding_name = !line[1].equals("")?line[1].trim():null;
                    String folder_name = !line[3].equals("")?line[3].trim():null;
                    String organization = !line[2].equals("")?line[2].trim():null;
                    String country = !line[4].equals("")?line[4].trim():null;
                    String totalAmount = !line[5].equals("")?line[5].trim():null;
                    String contractStartDate = !line[6].equals("")?line[6].trim():null;
                    String contractEndDate = !line[7].equals("")?line[7].trim():null;

                    String firstInvoiceDate = !line[8].equals("")?line[8].trim():null;
                    String firstInvoiceNumber = !line[9].equals("")?line[9].trim():null;

                    String secondInvoiceDate = !line[10].equals("")?line[10].trim():null;
                    String secondInvoiceNumber = !line[11].equals("")?line[11].trim():null;

                    String firstPaymentAmount = !line[12].equals("")?line[12].trim():null;
                    String firstPaymentDate = !line[13].equals("")?line[13].trim():null;
                    String firstPaymentOtherCosts = !line[14].equals("")?line[14].trim():null;
                    String firstPaymentTransferCost = !line[15].equals("")?line[15].trim():null;

                    String secondPaymentAmount = !line[16].equals("")?line[16].trim():null;
                    String secondPaymentDate = !line[17].equals("")?line[17].trim():null;
                    String secondPaymentOtherCosts = !line[18].equals("")?line[18].trim():null;
                    String secondPaymentTransferCost = !line[19].equals("")?line[19].trim():null;


                    List<Object> orgs =  organizationManager.search(organization);
                    if(orgs == null)
                        LOGGER.debug("Organization " + organization +  "  not exists!");

                    Organization org = (Organization) organizationManager.search(organization).get(0);
                    bid = this.initializeBid(funding_name,id,country,org,totalAmount,contractStartDate,contractEndDate);
                    LOGGER.debug("Bid initialized!");

                    bid.setFirstInvoice(this.uploadInvoiceFile(path,folder_name,FIRST_INVOICE_PDF,
                            firstInvoiceDate,firstInvoiceNumber));
                    LOGGER.debug("First invoice ready!");

                    bid.setSecondInvoice(this.uploadInvoiceFile(path,folder_name,SECOND_INVOICE_PDF,
                            secondInvoiceDate,secondInvoiceNumber));
                    LOGGER.debug("Second invoice ready!");

                    bid.setFirstPaymentDocument(this.uploadReceiptFile(path,folder_name,FIRST_PAYMENT_PDF,
                            firstPaymentAmount,firstPaymentDate,firstPaymentOtherCosts,firstPaymentTransferCost));
                    LOGGER.debug("First payment ready!");

                    bid.setSecondPaymentDocument(this.uploadReceiptFile(path,folder_name,SECOND_PAYMENT_PDF,
                            secondPaymentAmount,secondPaymentDate,secondPaymentOtherCosts,secondPaymentTransferCost));
                    LOGGER.debug("Second payment ready!");

                    bid.setContract(this.uploadContract(path,folder_name,CONTRACT_PDF));
                    LOGGER.debug("Contract ready!");
                    alternativeFundingBidDao.save(bid);
                }

            } catch (IOException | ParseException e) {
                LOGGER.debug(e);
            }
        }

    }

    private eu.dnetlib.goldoa.domain.File uploadContract(String basePath, String folder_name, String contract) throws IOException {

        String fullPath = null;
        URL url = null;
        URLConnection urlConnection = null;
        InputStream inputStream = null;
        String contentType = null;
        eu.dnetlib.goldoa.domain.File contractFile = null;
        try {
            fullPath = basePath + folder_name + "/" +  (URLEncoder.encode(contract, "UTF-8").replace("+", "%20"));
            url = new URL(fullPath);
            urlConnection = url.openConnection();
            inputStream = urlConnection.getInputStream();
            contentType = urlConnection.getContentType();
            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
            IOUtils.copy(inputStream, baos);
            IOUtils.closeQuietly(baos);

            contractFile = new eu.dnetlib.goldoa.domain.File();
            contractFile.setId(invoiceManager.getFileId());
            contractFile.setMimetype(contentType);
            contractFile.setFile(baos.toByteArray());
        } catch (IOException e) {
            LOGGER.debug(e);
        }

        return contractFile;
    }

    private BankTransferReceipt uploadReceiptFile(String basePath, String folder_name, String receipt,
                                                  String paymentAmount, String paymentDate,
                                                  String paymentOtherCosts, String paymentTransferCost) throws ParseException {

        String fullPath = null;
        Invoice invoice = null;
        BankTransferReceipt bankTransferReceipt = null;
        URL url = null;
        URLConnection urlConnection = null;
        InputStream inputStream = null;
        String contentType = null;
        try {
            fullPath = basePath + folder_name + "/" + (URLEncoder.encode(receipt, "UTF-8").replace("+", "%20"));
            url = new URL(fullPath);
            urlConnection = url.openConnection();
            inputStream = urlConnection.getInputStream();
            contentType = urlConnection.getContentType();

            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
            IOUtils.copy(inputStream, baos);
            IOUtils.closeQuietly(baos);
            bankTransferReceipt = new BankTransferReceipt();
            bankTransferReceipt.setContent(baos.toByteArray());
            bankTransferReceipt.setContentType(contentType);
            bankTransferReceipt.setAmount(Double.valueOf(paymentAmount));
            Date parsedDate = new SimpleDateFormat("yyyy-MM-dd").parse(paymentDate);
            Timestamp st = new java.sql.Timestamp(parsedDate.getTime());
            bankTransferReceipt.setDate(st);
            bankTransferReceipt.setOtherCosts(Double.valueOf(paymentOtherCosts));
            bankTransferReceipt.setTransferCost(Double.valueOf(paymentTransferCost));
        } catch (IOException e) {
            LOGGER.debug(e);
        }
        return bankTransferReceipt;

    }

    private AlternativeFundingBid initializeBid(String folder_name, String id, String country,
                                                Organization org, String totalAmount, String contractStartDate,
                                                String contractEndDate) {

        AlternativeFundingBid bid = new AlternativeFundingBid();
        bid.setBidName(folder_name);
        bid.setId(alternativeFundingBidDao.getIdSeq());
        bid.setCountry(alternativeFundingBidDao.getCountry(country));
        bid.setBidNo(Integer.valueOf(bid.getId()));
        bid.setTotalAmountRequested(Double.parseDouble(totalAmount));
        bid.setFirstPayment(Double.parseDouble(totalAmount)/2);
        bid.setSecondPayment(Double.parseDouble(totalAmount)/2);
        bid.setOrganization(org);
        bid.setRound(FIRST_ROUND);
        try {
            if(contractStartDate != null){
                Date parsedStartDate = new SimpleDateFormat("yyyy-MM-dd").parse(contractStartDate);
                Timestamp start = new java.sql.Timestamp(parsedStartDate.getTime());
                bid.setContractStartDate(start);
            }

            if(contractEndDate != null){
                Date parsedEndDate = new SimpleDateFormat("yyyy-MM-dd").parse(contractEndDate);
                Timestamp end = new java.sql.Timestamp(parsedEndDate.getTime());
                bid.setContractEndDate(end);
            }
        } catch (ParseException e) {
            LOGGER.debug("Start or end date null! ");
        }
        return bid;

    }

    private Invoice uploadInvoiceFile(String basePath, String folder_name, String invoicePdf,
                                      String invoiceDate, String invoiceNumber) throws ParseException {

        String fullPath = null;
        Invoice invoice = null;
        URL url = null;
        URLConnection urlConnection = null;
        InputStream inputStream = null;
        String contentType = null;
        try {
            fullPath = basePath + folder_name + "/" + (URLEncoder.encode(invoicePdf, "UTF-8").replace("+", "%20"));
            LOGGER.debug(fullPath);
            url = new URL(fullPath);
            urlConnection = url.openConnection();
            inputStream = urlConnection.getInputStream();
            contentType = urlConnection.getContentType();
            invoice = new Invoice();
            invoice.setSource("portal");
            invoice.setNumber(invoiceNumber);
            Date parsedStartDate = new SimpleDateFormat("yyyy-MM-dd").parse(invoiceDate);
            Timestamp st = new java.sql.Timestamp(parsedStartDate.getTime());
            invoice.setDate(st);
            invoice = invoiceManager.saveInvoice(invoice);
            invoice = invoiceManager.uploadInvoice(invoice.getId(), contentType, inputStream);
            invoiceManager.saveInvoice(invoice);
        } catch (IOException | ManagerException e) {
            LOGGER.debug(e);
        }
        return invoice;
    }



    @Override
    public List<AlternativeFundingBid> getFundingBidsByRound(String round) {
        return alternativeFundingBidDao.getFundingBidsByRound(round);
    }

    @Override
    public List<AlternativeFundingBid> getAllFundingBids() {
        return alternativeFundingBidDao.getAllFundingBids();
    }

    @Override
    public AlternativeFundingBid getAlternativeFundingBidsById(String id) throws Exception {
        return alternativeFundingBidDao.getById(id);
    }

    @Override
    public List<Object> getDocuments(String id) throws Exception {

        List<Object> docs = new ArrayList<>();
        AlternativeFundingBid bid = getAlternativeFundingBidsById(id);

        docs.add(bid.getFirstPaymentDocument());
        docs.add(bid.getSecondPaymentDocument());
        docs.add(bid.getFirstInvoice());
        docs.add(bid.getSecondInvoice());
        docs.add(bid.getContract());
        return docs;
    }

    @Override
    public BankTransferReceipt getBankTransferReceipt(String id, String mode) throws Exception {

        AlternativeFundingBid bid = getAlternativeFundingBidsById(id);

        if(mode.equals(FIRST_PAYMENT))
            return bid.getFirstPaymentDocument();
        else
            return bid.getSecondPaymentDocument();
    }

    @Override
    public Invoice getInvoice(String id, String mode) throws Exception {
        AlternativeFundingBid bid = getAlternativeFundingBidsById(id);

        if(mode.equals(FIRST_INVOICE))
            return bid.getFirstInvoice();
        else
            return bid.getSecondInvoice();
    }

    @Override
    public eu.dnetlib.goldoa.domain.File getContract(String id) throws Exception {
        AlternativeFundingBid bid = getAlternativeFundingBidsById(id);
        return bid.getContract();
    }

    @Override
    public void save(AlternativeFundingBid bid) {
        alternativeFundingBidDao.save(bid);
    }

    @Override
    public Country getCountry(String country) {
        return alternativeFundingBidDao.getCountry(country);
    }
}
