package com.alexanderlogistics.migration;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import org.imixs.melman.FormAuthenticator;
import org.imixs.melman.RestAPIException;
import org.imixs.melman.WorkflowClient;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.exceptions.PluginException;
import org.junit.Before;
import org.junit.Test;

import junit.framework.Assert;

public class MigrationMahnerAusziffern {

    List<Rechnung> rechnungen = new ArrayList<Rechnung>();

    WorkflowClient workflowCLient = null;
    String user = "archive";
    String ps = "archive4imixs";
    String restAPI = "https://alexander-logistics.office-workflow.de/api";
    int countProcessed=0;
    int notFound=0;
    int count = 0;
    @Before
    public void setup() throws PluginException, RestAPIException {
        rechnungen = new ArrayList<Rechnung>();
        // Init Workflow Client
        workflowCLient = new WorkflowClient(restAPI);
        FormAuthenticator formAuth = new FormAuthenticator(restAPI, user, ps);
        workflowCLient.registerClientRequestFilter(formAuth);
        
        ItemCollection ding = workflowCLient.getWorkitem("1ef4757f-69ae-4ec1-8ba1-01d380d046e7");
        
        if (ding!=null) {
            System.out.println("pip");
        } else {
            System.out.println("pap");
            
        }
    }

    /**
     * Diese Test Method wandelt die Datei OPD_migration_230126.csv in eine EXTV
     * Datev Datei um, welche wir dann für einen einmaligen Import der
     * Rechnugnsdaten verwenden können.
     * @throws PluginException 
     * @throws RestAPIException 
     * 
     */
    @Test
    public void anlysiere() throws RestAPIException, PluginException {

        System.out.println("***********************");
        System.out.println("* OP Listen Auszifferliste *");
        System.out.println("***********************");

        String filename_input = "datev/OPD_migration_230126.csv";

        FileInputStream fis;
        BufferedReader br = null;
        try {
            ClassLoader classLoader = this.getClass().getClassLoader();
            File inputFile = new File(classLoader.getResource(filename_input).getFile());
            Assert.assertTrue(inputFile.exists());
            fis = new FileInputStream(inputFile);
            DataInputStream in = new DataInputStream(fis);
            br = new BufferedReader(new InputStreamReader(in, "ISO-8859-1"));

            // read the first line containing the field names
            String fieldnames = br.readLine();

            Assert.assertTrue(fieldnames.contains("Kontonummer"));

            String line;
           

            while ((line = br.readLine()) != null) {

                String[] data = line.split(";(?=([^\"]*\"[^\"]*\")*[^\"]*$)", 999);

                if (data.length != 90) {
                    System.out.println("Fehlerhafte Daten in Zeile " + count);
                    System.out.println(line);
                    Assert.fail();
                }

                analyzeLine(data, count);
                count++;
              
//                if (count>2800) {
//                    break;
//                }
               
            }
            System.out.println("=================================================");
            System.out.println("... fininshed - read " + count + " lines.");
            System.out.println("    " + notFound + " Rechnungen nicht mehr aktiven Bestand");
            System.out.println("    processed " + countProcessed + " Rechnungen in total");
            

        } catch (IOException e) {
            e.printStackTrace();
            Assert.fail();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    Assert.fail();
                }
            }
        }
    }

    /**
     * Prüft eine einzelen Datenzeile
     * 
     * @param writer
     * @param data
     * @throws IOException
     * @throws RestAPIException
     * @throws PluginException 
     */
    private void analyzeLine(String[] data, int line) throws IOException, RestAPIException, PluginException {
      
        System.out.println("...line " + count);
        String rechnungsNummer = data[2];
        
        
        
        String rechnungsDatum = data[3];
        String faelligkeit = data[4];
        String saldo = data[7];
        String zahlung = data[6];
        // vertasuchen
        if (faelligkeit.length() == 8) {
            faelligkeit = faelligkeit.substring(4, 8) + faelligkeit.substring(2, 4) + faelligkeit.substring(0, 2);
        } else {
            faelligkeit = "20230125";
        }
        String text = data[18];
        String basisumsatz = "0,00";
        String umsatz = data[5];
        if ("0,00".equals(umsatz)) {
            umsatz = data[6];
        }
        if ("0,00".equals(umsatz)) {
            System.out.println("ACHTUNG - Fehler in Spalte 5 bzw. 6 in zeile " + line);
        }
        String sh = data[8];

        String wkz = data[9];
        if (isEmpty(wkz)) {
            wkz = "\"EUR\"";
        } else {
            umsatz = data[10];
            basisumsatz = data[5];
            if ("0,00".equals(basisumsatz)) {
                basisumsatz = data[6];
            }

        }
        String kurs = data[11];

        String gegenkonto = data[0];
        String konto = data[12];

        boolean skip = false;

        // umdrehen von sh
        if ("\"H\"".equals(sh)) {
            sh = "\"S\"";
        } else {
            sh = "\"H\"";
        }

        // cache diese Information
        Rechnung rech = new Rechnung(gegenkonto, rechnungsNummer, umsatz, sh, wkz);

        // nur wenn die Rechnung in Office ist
        if (findRechnung(rech.rechnungsNummer)) {
            
            Rechnung matchingRech = findMatch(rech);
            if (matchingRech != null) {
                System.out.println("___________________________________________________");
                System.out.println(" Bitte Ausziffern : " + rech.konto + "  = " + rech.rechnungsNummer + "  ->   "
                        + matchingRech.rechnungsNummer);
               
                // Starte RestAPI call.....
                processRechnungen(rech.rechnungsNummer, matchingRech.rechnungsNummer);
               

                // matchingRech muss aus dem cach raus
                boolean removeresult=rechnungen.remove(matchingRech);
                if (removeresult==false) {
                    System.out.println(" ACHTUNG WIR haben ein Proboem  ");
                    throw new PluginException("ERROR", "ERROR", "Nichzt im chache!!!!!!");
                }
                
                //throw new PluginException("STOP", "STOP", "STOP!!!!!!");   
                
            } else {
                // ab in den cache
                rechnungen.add(rech);
               
            }

        } else {
            // die rechnung gibts nicht und es gibt nicths zu prüfen
        }
        
        
       

    }

    private boolean isEmpty(String data) {
        return (data.isEmpty() || "\"\"".equals(data));
    }

    /**
     * Diese Methode schließt die Rechnungen mit den übergebenen Rechnungsnummer ab
     * 
     * Beispiel: Bitte Ausziffern : 17755 = "190818" -> "190313"
     * 
     * @throws UnsupportedEncodingException
     * @throws RestAPIException
     * @throws PluginException 
     */
    private void processRechnungen(String rech1, String rech2) throws RestAPIException, UnsupportedEncodingException, PluginException {
        // erstmal die Kanddaten suchen
        String query = "type:workitem AND $modelversion:rechnungsausgang-de-1.0 AND (invoice.number:" + rech1
                + " OR invoice.number:" + rech2 + ")";
        System.out.println(query);
        List<ItemCollection> result = workflowCLient.searchDocuments(query);
        if (result == null || result.size() != 2) {
            System.out.println("Fehler - Rechnungen nicht gefunden!");
            notFound=notFound+2;
            return;
        }
        
        System.out.println("Ich beginne jetzt mit Gabys Workflow...");
        ItemCollection rechItemCol=result.get(0);
        rechItemCol.event(420);
        workflowCLient.processWorkitem(rechItemCol);

        rechItemCol=result.get(1);
        rechItemCol.event(420);
        workflowCLient.processWorkitem(rechItemCol);

        countProcessed=countProcessed+2;
    }

    
    /**
     * Teste ob es diese Rechnung im Office gibt.
     * 
     * @param rech1
     * @throws RestAPIException
     * @throws UnsupportedEncodingException
     * @throws PluginException
     */
    private boolean findRechnung(String rech1) throws RestAPIException, UnsupportedEncodingException, PluginException {
        // erstmal die Kanddaten suchen
        String query = "type:workitem AND $modelversion:rechnungsausgang-de-1.0 AND (invoice.number:" + rech1+ ")";
        //System.out.println(query);
        List<ItemCollection> result = workflowCLient.searchDocuments(query);
        if (result != null && result.size() == 1) {
            //System.out.println("    OK - Rechnungen  gefunden!");
            return true;
        }
        
        return false;
    }

    
    /**
     * Hilfsmethdoe die prüft ob es zu diesr Rechnung shcon eine passende
     * Gegenrechnung gibt.
     * 
     * @param rech
     * @return
     */
    private Rechnung findMatch(Rechnung rech) {

        // gehen über all rechnungen und vergleiche alle eigenschaften
        for (Rechnung matchRech : rechnungen) {

            if (rech.rechnungsNummer.equals(matchRech.rechnungsNummer)) {
                System.out.println(" !! Rechnungsnummer Doppelt : " + rech.rechnungsNummer);
            }

            if (rech.konto.equals(matchRech.konto) && rech.umsatz.equals(matchRech.umsatz)
                    && rech.wkz.equals(matchRech.wkz) && !rech.sh.equals(matchRech.sh)) {
                // Hurrar wir habne eine treffer
                return matchRech;
            }

        }

        // nix gefunden
        return null;
    }

    class Rechnung {
        String konto;
        String rechnungsNummer;
        String umsatz;
        String sh;
        String wkz;

        public Rechnung(String konto, String rechnungsNummer, String umsatz, String sh, String wkz) {
            super();
            this.konto = konto;
            this.rechnungsNummer = rechnungsNummer;
            this.umsatz = umsatz;
            this.sh = sh;
            this.wkz = wkz;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + getEnclosingInstance().hashCode();
            result = prime * result + Objects.hash(konto, rechnungsNummer, sh, umsatz, wkz);
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Rechnung other = (Rechnung) obj;
            if (!getEnclosingInstance().equals(other.getEnclosingInstance()))
                return false;
            return Objects.equals(konto, other.konto) && Objects.equals(rechnungsNummer, other.rechnungsNummer)
                    && Objects.equals(sh, other.sh) && Objects.equals(umsatz, other.umsatz)
                    && Objects.equals(wkz, other.wkz);
        }

        private MigrationMahnerAusziffern getEnclosingInstance() {
            return MigrationMahnerAusziffern.this;
        }

       

    }

}
