package systems.sdw;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.UUID;

import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.font.Standard14Fonts;
import org.mustangproject.Allowance;
import org.mustangproject.BankDetails;
import org.mustangproject.CashDiscount;
import org.mustangproject.Charge;
import org.mustangproject.Contact;
import org.mustangproject.Invoice;
import org.mustangproject.Item;
import org.mustangproject.Product;
import org.mustangproject.TradeParty;
import org.mustangproject.ZUGFeRD.PDFAConformanceLevel;
import org.mustangproject.ZUGFeRD.Profile;
import org.mustangproject.ZUGFeRD.ZUGFeRDExporterFromA3;
import org.mustangproject.ZUGFeRD.ZUGFeRDImporter;

import systems.sdw.basetech.json.JSONArray;
import systems.sdw.basetech.json.JSONException;
import systems.sdw.basetech.json.JSONObject;

public class ZugferdUtil {


	public static void main(String[] args) throws IOException, JSONException{

		
//		readZugferdDaten(new File("/Users/benediktwismans/tmp/rechnung_sdw.2025.06253.pdf"));
//		
//		System.exit(0);
		
		
		String originalPath="/Users/benediktwismans/tmp/rechnung.pdf";
		//String originalPath="/Users/benediktwismans/tmp/rechnung_sdw.2025.06234.pdf";
		
		String copyPath="/Users/benediktwismans/tmp/zugferd.pdf";
	    Files.copy(Path.of(originalPath), Path.of(copyPath), StandardCopyOption.REPLACE_EXISTING);

	    //	PDF
		File pdf=new File(copyPath);

		// JSON
//			String content = Files.readString(Path.of("/Users/benediktwismans/tmp/sdw.json"), Charset.forName("UTF-8"));
			String content = Files.readString(Path.of("/Users/benediktwismans/tmp/zugferd.json"), Charset.forName("UTF-8"));
		JSONObject json=new JSONObject(content);
		System.out.println(json.toString(3));
		
		createZugferdPDF(pdf, json);

	}
	
	public static File createZugferdPDF(File pdf, JSONObject json) {

		if (pdf!=null && json!=null) {

			try {
				// A1 und PDFA funktionieren nicht.
				ZUGFeRDExporterFromA3 ze=new ZUGFeRDExporterFromA3().load(pdf.getCanonicalPath());

				ze.setProducer("SDW Bischberg Dipl.Wirtsch.-Inf. Benedikt Wismans");
				ze.setCreator("Benedikt Wismans");

				ze.setZUGFeRDVersion(2);
				ze.setConformanceLevel(PDFAConformanceLevel.UNICODE);
				ze.setProfile("EXTENDED");
				
				/*
				 * Mustangproject checks if the input PDF/A file looks halfway valid and 
				 * the XML data contains <rsm:CrossIndustry which is the case for both 
				 * ZF1 (CrossIndustryDocument) and ZF2 files (CrossIndustryInvoice).
				 * Insert your (validated) XML here.
				 */
				System.out.println("Injecting ZUGFeRD-Data");
				injectXML(ze, json);

				System.out.println("Writing ZUGFeRD-PDF");
				ze.export(pdf.getCanonicalPath());
				ze.close();
				
				return appendZugferdDaten(pdf);

			} catch (IOException | JSONException e) {
				e.printStackTrace();
			}
		}
		return null;
	}


	public static void injectXML(ZUGFeRDExporterFromA3 ze, JSONObject json) throws IOException, JSONException {

		JSONObject sender=json.getJSONObject("sender");
		JSONObject bankdetails=sender.getJSONObject("bankdetails");

		JSONObject recipient=json.getJSONObject("recipient");
		JSONObject contact=recipient.getJSONObject("contact");

		//@SuppressWarnings("deprecation")
		Invoice invoice=new Invoice()
		.setDueDate(json.getAmericanDate("faelligkeitsdatum"))
		.setIssueDate(json.getAmericanDate("rechnungsdatum"))
		.setDeliveryDate(json.getAmericanDate("leistungsdatum"))

		.setSender(new TradeParty(sender.getString("name"), sender.getString("strasse"), sender.getString("plz"), sender.getString("ort"), sender.getString("land"))
				.addVATID(sender.getString("ustid"))
				//	.addTaxID(sender.getString("steuernummer"))
				.addBankDetails(new BankDetails(bankdetails.getString("iban"), bankdetails.getString("swift"))))    

		.setRecipient(new TradeParty(recipient.getString("name"), recipient.getString("strasse"), recipient.getString("plz"), recipient.getString("ort"), recipient.getString("land"))
				.setContact(new Contact(contact.getString("name"), contact.getString("telefon"), contact.getString("email")))).setNumber(json.getString("rechnungsnummer"));

		JSONArray positionen=json.getJSONArray("positionen");
		for (int i=0; i<=positionen.length()-1; i++) {
			JSONObject position=positionen.getJSONObject(i);
			JSONObject produkt=position.getJSONObject("produkt");

//			System.out.println(i);
//			System.out.println(position.toString(2));
			
			Item item=new Item(
					new Product(produkt.getString("name"), produkt.getString("beschreibung", ""), produkt.getString("einheit"), new BigDecimal(produkt.getString("steuersatz"))),
					new BigDecimal(position.getString("preis")), 
					new BigDecimal(position.getString("menge")));
			
			if (position.getDouble("rabatt")>0) {
				item.addAllowance(new Allowance().setPercent(new BigDecimal(position.getString("rabatt"))).setTaxPercent(new BigDecimal(produkt.getString("steuersatz"))));

//				Charge ist ein Zuschlag, wird nicht unterstützt				
//				item.addCharge(new Charge().setPercent(new BigDecimal(position.getString("rabatt"))).setTaxPercent(new BigDecimal(produkt.getString("steuersatz"))));
			}
			invoice.addItem(item);
		}
		
		if (json.getDouble("skonto")>0 && json.getInteger("skontotage")>0) {
			
			invoice.addCashDiscount(new CashDiscount(new BigDecimal(json.getString("skonto")), json.getInteger("skontotage")));
		}
		
		ze.setTransaction(invoice);
	}

	private static void write(PDPageContentStream contentStream, int textx, int texty, String text) throws IOException  {

		contentStream.beginText();
		contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.COURIER), 12);

		contentStream.newLineAtOffset(textx,texty);
		contentStream.showText(text);
		contentStream.endText();
	}


	public static void readZugferdDaten(File pdf) throws IOException  {
		
		ZUGFeRDImporter zi=new ZUGFeRDImporter(pdf.getCanonicalPath());

		System.out.println("getInvoiceID " + zi.getInvoiceID());
		System.out.println("getInvoiceCurrencyCode " + zi.getInvoiceCurrencyCode());
		System.out.println("getDueDate " + zi.getDueDate());
		System.out.println("getIBAN " + zi.getIBAN());		
		System.out.println("getBIC " + zi.getBIC());	
		System.out.println("getLineTotalAmount " + zi.getLineTotalAmount());
		System.out.println("getTaxTotalAmount " + zi.getTaxTotalAmount());
		System.out.println("getAmount " + zi.getAmount());
		String profil="getZUGFeRDProfil "+zi.getZUGFeRDProfil();
		String version="getVersion ?";
		try {
			version="getVersion "+String.valueOf(zi.getVersion());
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		System.out.println(profil);
		System.out.println(version);
	}

	
	
	public static File appendZugferdDaten(File pdf) throws IOException  {
		
		ZUGFeRDImporter zi=new ZUGFeRDImporter(pdf.getCanonicalPath());

		String[] zugferddata=new String[10];
		zugferddata[0]="getInvoiceID " + zi.getInvoiceID();
		zugferddata[1]="getInvoiceCurrencyCode " + zi.getInvoiceCurrencyCode();
		zugferddata[2]="getDueDate " + zi.getDueDate();
		zugferddata[3]="getIBAN " + zi.getIBAN();		
		zugferddata[4]="getBIC " + zi.getBIC();	
		zugferddata[5]="getLineTotalAmount " + zi.getLineTotalAmount();
		zugferddata[6]="getTaxTotalAmount " + zi.getTaxTotalAmount();
		zugferddata[7]="getAmount " + zi.getAmount();
	
		org.mustangproject.ZUGFeRD.PostalTradeAddress buyer=zi.getBuyerTradePartyAddress();
		zugferddata[8]="getBuyerTradeParty "+zi.getBuyerTradePartyName(); //+" "+buyer.getPostcodeCode()+" "+buyer.getCityName()+" "+buyer.getLineOne();
		
		org.mustangproject.ZUGFeRD.PostalTradeAddress seller=zi.getSellerTradePartyAddress();
		zugferddata[9]="getSellerTradeParty "+zi.getHolder(); //+" "+seller.getPostcodeCode()+" "+seller.getCityName()+" "+seller.getLineOne();

		
		
		String profil="getZUGFeRDProfil "+zi.getZUGFeRDProfil();
		String version="getVersion ?";
		try {
			version="getVersion "+String.valueOf(zi.getVersion());
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		System.out.println(zugferddata[0]);
		System.out.println(zugferddata[1]);
		System.out.println(zugferddata[2]);
		System.out.println(zugferddata[3]);
		System.out.println(zugferddata[4]);
		System.out.println(zugferddata[5]);
		System.out.println(zugferddata[6]);
		System.out.println(zugferddata[7]);
		System.out.println(zugferddata[8]);
		System.out.println(zugferddata[9]);
		
		System.out.println(profil);
		System.out.println(version);
	
		
		PDDocument doc = Loader.loadPDF(pdf);
		PDPage page = new PDPage(PDRectangle.A4);
		doc.addPage(page);

		PDPageContentStream contentStream = new PDPageContentStream(doc, page);

		write(contentStream, 30,750, "Diese Rechnung im PDF-Format enthält einen maschinenlesbaren Teil, der");
		write(contentStream, 30,735, "dem ZUGFeRD-Standard Version 2 entspricht.");

		write(contentStream, 30,720, "Diese Seite, die nicht zur Rechnung gehört, dient dazu, die Integrität");
		write(contentStream, 30,705, "dieser Daten zu dokumentieren. Dazu wurden die relevantesten Daten ");
		write(contentStream, 30,690, "NACH dem Hinzufügen zu diesem PDF-Dokument wieder ausgelesen und");
		write(contentStream, 30,675, "sind im folgenden aufgeführt.");

		write(contentStream, 30,600, zugferddata[0]);
		write(contentStream, 30,580, zugferddata[1]);
		write(contentStream, 30,560, zugferddata[2]);
		write(contentStream, 30,540, zugferddata[3]);
		write(contentStream, 30,520, zugferddata[4]);
		write(contentStream, 30,500, zugferddata[5]);
		write(contentStream, 30,480, zugferddata[6]);
		write(contentStream, 30,460, zugferddata[7]);
		write(contentStream, 30,440, zugferddata[8]);
		write(contentStream, 30,420, zugferddata[9]);

		write(contentStream, 30,380, profil);
		write(contentStream, 30,360, version);
		
		contentStream.close();

		//	create target file in same directory.
		//	do not use input file formoutput! 
		File targetFile=new File(pdf.getParent()+"/"+UUID.randomUUID());
		doc.save(targetFile);

		doc.close();
		
		return targetFile;
	}







}
