package hr.com.port.ips.eracun.mapperi;

import hr.com.port.connectionPool.__Pool;
import hr.com.port.eracun.codelists.CurrencyCode;
import hr.com.port.eracun.codelists.DocumentTypeCode;
import hr.com.port.ips.modeli.FakturaModel;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.logging.Level;
import hr.com.port.functions.Convert;
import hr.com.port.functions.DbFunctions;
import hr.com.port.functions.Functions;
import hr.com.port.ips.modeli.DokumentTotalModel;
import hr.com.port.ips.modeli.FakturaStavkaModel;
import hr.com.port.modeli.DokumentPorezModel;
import hr.com.port.modeli.KorisnikModel;
import hr.com.port.modeli.PodaciFirmaModel;
import javafx.stage.Stage;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import oasis.names.specification.ubl.schema.xsd.invoice_2.InvoiceType;
import hr.com.port.modeli.PlacanjeModel;
import hr.com.port.modeli.PopustTrosakModel;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
import oasis.names.specification.ubl.schema.xsd.commonaggregatecomponents_2.*;
import oasis.names.specification.ubl.schema.xsd.commonbasiccomponents_2.*;
import oasis.names.specification.ubl.schema.xsd.commonextensioncomponents_2.*;
import oasis.names.specification.ubl.schema.xsd.commonsignaturecomponents_2.UBLDocumentSignaturesType;
import oasis.names.specification.ubl.schema.xsd.signatureaggregatecomponents_2.SignatureInformationType;
import org.apache.log4j.Logger;

public class FakturaEracunMapper {

	static Logger logger = Logger.getLogger(FakturaEracunMapper.class);

	public static void populateInvoice(InvoiceType invoice, String base64Pdf, FakturaModel faktura, int godina, Connection... defaultConnection){
		Connection conn;
		if (defaultConnection.length > 0) {
			conn = defaultConnection[0];
		} else {
			conn = new __Pool(null).getConnection();
		}
		try {
			DatatypeFactory df = null;
			try {
				df = DatatypeFactory.newInstance();
			} catch (DatatypeConfigurationException ex) {
				java.util.logging.Logger.getLogger(FakturaModel.class.getName()).log(Level.SEVERE, null, ex);
			}
			
			String brojRacuna = faktura.getBroj() + "/" + faktura.getOpp().getOznaka() + "/" + faktura.getOnu().getOznaka();
			String brojRacunaPdf = faktura.getBroj() + "-" + faktura.getOpp().getOznaka() + "-" + faktura.getOnu().getOznaka();
			
			XMLGregorianCalendar dateNow = df.newXMLGregorianCalendar(LocalDate.now().toString());			
			
			// ---- UBLExtensions (prazan, ali valjan sadržaj) ----
			UBLExtensionsType ublExtensions = new UBLExtensionsType();
			UBLExtensionType ext = new UBLExtensionType();

			UBLDocumentSignaturesType ublDocSigs = new UBLDocumentSignaturesType();
			SignatureInformationType sigInfo = new SignatureInformationType();
			// ne postavljamo ništa u sigInfo; samo ga dodamo kao “placeholder”
			ublDocSigs.getSignatureInformation().add(sigInfo);

			ExtensionContentType extContent = new ExtensionContentType();
			extContent.setUBLDocumentSignatures(ublDocSigs);

			ext.setExtensionContent(extContent);
			ublExtensions.getUBLExtension().add(ext);
			invoice.setUBLExtensions(ublExtensions);
			
			// ---- CustomizationID (HR CIUS/EXT 2025) ----
			CustomizationIDType customizationID = new CustomizationIDType();
			customizationID.setValue("urn:cen.eu:en16931:2017#compliant#urn:mfin.gov.hr:cius-2025:1.0#conformant#urn:mfin.gov.hr:ext-2025:1.0");
			//customizationID.setValue("urn:cen.eu:en16931:2017"); // "STARA" varijanta po normi
			invoice.setCustomizationID(customizationID);
			
			// ProfileID - tip poslovnog procesa
			ProfileIDType profileID = new ProfileIDType();
			profileID.setValue(faktura.getTipProcesa()); // P1 = izdavanje računa za isporuke robe i usluga prema narudžbenicama, na temelju ugovora
			// TODO ugraditi opcije za račun s referencama, odobrenja ili račune s negativnim iznosima
			invoice.setProfileID(profileID);
			
			// broj računa
			IDType id = new IDType();			
			id.setValue(brojRacuna);
			invoice.setID(id);
			
			// datum izdavanja
			IssueDateType issueDate = new IssueDateType();
			issueDate.setValue(Convert.toXMLDate(faktura.getDatum()));
			invoice.setIssueDate(issueDate);
			
			// vrijeme izdavanja
			IssueTimeType issueTime = new IssueTimeType();
			issueTime.setValue(Convert.toXMLTime(faktura.getVrijeme()));
			invoice.setIssueTime(issueTime);
						
			// datum valute plaćanja
			DueDateType dueDate = new DueDateType();
			dueDate.setValue(Convert.toXMLDate(faktura.getDatum(), faktura.getRok()));
			invoice.setDueDate(dueDate);
			
			// InvoiceTypeCode
			InvoiceTypeCodeType invoiceTypeCode = new InvoiceTypeCodeType();
			invoiceTypeCode.setValue(DocumentTypeCode._380.getCode()); // TODO provjeriti je li za fakturu uvijek 380
			invoice.setInvoiceTypeCode(invoiceTypeCode);
			
			//oznaka operatera - TRENUTNO SE ŠALJE KAO NOTE
			NoteType note = new NoteType();
			note.setValue("Oznaka operatera: " + faktura.getOznakaOperatera());			
			invoice.getNote().add(note);
			
			//odgovorna osoba - TRENUTNO SE ŠALJE KAO NOTE
			//note = new NoteType();
			//KorisnikModel korisnik = KorisnikModel.fromOib(faktura.getOib_operatera(), null, false);
			//note.setValue("Odgovorna osoba: " + korisnik.getIme() + " " + korisnik.getPrezime());
			//invoice.getNote().add(note);
			
			// napomena - Note - free-form text notes
			if (faktura.getOpis().length() > 0){
				note = new NoteType();
				note.setValue(faktura.getOpis());
				invoice.getNote().add(note);
			}
			
			// datum obveze - TaxPointDate - date when tax becomes applicable)
			//TaxPointDateType taxPointDate = new TaxPointDateType();
			//taxPointDate.setValue(Convert.toXMLDate(faktura.getDatumObveze()));
			//invoice.setTaxPointDate(taxPointDate);
			
			// DocumentCurrencyCode (optional: currency code for the document totals)
			DocumentCurrencyCodeType documentCurrencyCode = new DocumentCurrencyCodeType();
			documentCurrencyCode.setValue(CurrencyCode.EUR.name());
			invoice.setDocumentCurrencyCode(documentCurrencyCode);
			
			/*// AccountingCost (optional: buyer's accounting cost as text)
			AccountingCostType accountingCost = new AccountingCostType();
			accountingCost.setValue("example-value");
			invoice.setAccountingCost(accountingCost);*/
			
			// InvoicePeriod (optional: period to which the invoice applies)
			//PeriodType invoicePeriod = new PeriodType();
			//StartDateType startDate = new StartDateType();
			//startDate.setValue(dateNow);
			//invoicePeriod.setStartDate(startDate);
			//EndDateType endDate = new EndDateType();
			//endDate.setValue(dateNow);
			//invoicePeriod.setEndDate(endDate);
			//invoice.getInvoicePeriod().add(invoicePeriod);
			
			// referenca narudžbe - OrderReference (optional: reference to an associated Order)
			if(faktura.getRefNarudzbe()!=null && faktura.getRefNarudzbe().length() > 0){
				OrderReferenceType orderReference = new OrderReferenceType();
				IDType orderID = new IDType();
				orderID.setValue(faktura.getRefNarudzbe());
				orderReference.setID(orderID);
				invoice.setOrderReference(orderReference);
			}
			
			/*// BillingReference [0..*] (optional: reference to a billing document)
			BillingReferenceType billingReference = new BillingReferenceType();
			DocumentReferenceType billingDocRef = new DocumentReferenceType();
			IDType billingDocID = new IDType();
			billingDocID.setValue("example-value");
			billingDocRef.setID(billingDocID);
			billingReference.setInvoiceDocumentReference(billingDocRef);
			invoice.getBillingReference().add(billingReference);*/               ////  PRIMJER - OVAKO ĆE BITI DODAVANO KAD BUDE LISTA
			
			// referenca otpremnice - DespatchDocumentReference [0..*] (optional: reference to a despatch advice)
			if(faktura.getRefOtpremnice()!=null && faktura.getRefOtpremnice().length() > 0){
				DocumentReferenceType despatchDocRef = new DocumentReferenceType();
				IDType despatchID = new IDType();
				despatchID.setValue(faktura.getRefOtpremnice());
				despatchDocRef.setID(despatchID);
				invoice.getDespatchDocumentReference().add(despatchDocRef);
			}
			
			/*// ReceiptDocumentReference [0..*] (optional: reference to a receipt advice)
			DocumentReferenceType receiptDocRef = new DocumentReferenceType();
			IDType receiptID = new IDType();
			receiptID.setValue("example-value");
			receiptDocRef.setID(receiptID);
			invoice.getReceiptDocumentReference().add(receiptDocRef);*/       ////  PRIMJER - OVAKO ĆE BITI DODAVANO KAD BUDE LISTA
			
			/*// ContractDocumentReference [0..*] (optional: reference to a contract document)
			DocumentReferenceType contractDocRef = new DocumentReferenceType();
			IDType contractID = new IDType();
			contractID.setValue("example-value");
			contractDocRef.setID(contractID);
			invoice.getContractDocumentReference().add(contractDocRef);*/
			
			// AdditionalDocumentReference [0..*] (optional: reference to any additional document)			
			// reference na druge dokumente, može ih biti više, jedna od njih je i PDF vizualizacija
			DocumentReferenceType pdfPrilog = new DocumentReferenceType();
			IDType additionalID = new IDType();
			additionalID.setValue(brojRacuna);
			pdfPrilog.setID(additionalID);			
			
			DocumentDescriptionType desc = new DocumentDescriptionType();
			desc.setValue("Vizualizacija izvornika računa");
			pdfPrilog.getDocumentDescription().add(desc);
			
			AttachmentType attachment = new AttachmentType();
			EmbeddedDocumentBinaryObjectType embeddedPdf = new EmbeddedDocumentBinaryObjectType();
			embeddedPdf.setMimeCode("application/pdf");
			embeddedPdf.setFilename(brojRacunaPdf + ".pdf");
			byte[] pdfBytes = Base64.getDecoder().decode(base64Pdf);
			embeddedPdf.setValue(pdfBytes);
			attachment.setEmbeddedDocumentBinaryObject(embeddedPdf);			
			pdfPrilog.setAttachment(attachment);			
			
			invoice.getAdditionalDocumentReference().add(pdfPrilog);			
			
			
			/*// Signature (optional: electronic signature details)
			SignatureType signature = new SignatureType();
			IDType signatureID = new IDType();
			signatureID.setValue("example-value");
			signature.setID(signatureID);
			invoice.setSignature(signature);*/
			
			popuniStranke(invoice, faktura);
			popuniStavke(invoice, faktura);
			
			/*	// PayeeParty (optional: the payee, if different from the supplier)
			PartyType payeeParty = new PartyType();
			// Set a placeholder name for the payee
			PartyNameType payeePartyName = new PartyNameType();
			NameType payeeName = new NameType();
			payeeName.setValue("example-value");
			payeePartyName.setName(payeeName);
			payeeParty.getPartyName().add(payeePartyName);
			invoice.set
			
			// TaxRepresentativeParty (optional: tax representative party)
			PartyType taxRepresentativeParty = new PartyType();
			// Set a placeholder name for the tax representative
			PartyNameType taxRepName = new PartyNameType();
			NameType taxRepNameValue = new NameType();
			taxRepNameValue.setValue("example-value");
			taxRepName.setName(taxRepNameValue);
			taxRepresentativeParty.getPartyName().add(taxRepName);
			invoice.setTaxRepresentativeParty(taxRepresentativeParty);*/
			
			/*// Delivery [0..*] (optional: delivery information) // ne prolazi validaciju
			DeliveryType delivery = new DeliveryType();
			ActualDeliveryDateType actualDeliveryDate = new ActualDeliveryDateType();
			actualDeliveryDate.setValue(dateNow);
			delivery.setActualDeliveryDate(actualDeliveryDate);
			invoice.getDelivery().add(delivery);*/
			
			// način plaćanja PaymentMeans
			for(PlacanjeModel placanje : faktura.getPlacanja()){
				
				PaymentMeansType paymentMeans = new PaymentMeansType();
				
				// šifra (code)
				PaymentMeansCodeType paymentMeansCode = new PaymentMeansCodeType();
				paymentMeansCode.setValue(placanje.getNacin().getSifra()); //   NacinplacanjaCode._30.getCode() = plaćanje putem transakcijskog računa
				paymentMeans.setPaymentMeansCode(paymentMeansCode);
				
				// upute za plaćanje
				if(placanje.getUpute()!=null && placanje.getUpute().length()>0){
					InstructionNoteType instructionNote = new InstructionNoteType();
					instructionNote.setValue(placanje.getUpute());
					paymentMeans.getInstructionNote().add(instructionNote);
				}
				
				// model i poziv na broj
				if(placanje.getModel()!=null && placanje.getPozivNaBroj()!=null && placanje.getModel().length()>0 && placanje.getPozivNaBroj().length()>0 ){
					PaymentIDType paymentID = new PaymentIDType();
					paymentID.setValue("HR" + placanje.getModel() + " " + placanje.getPozivNaBroj());
					paymentMeans.getPaymentID().add(paymentID);
				}
				
				// IBAN
				if(placanje.getRacun().getBrojRacuna()!=null && placanje.getRacun().getBrojRacuna().length()>0){
					FinancialAccountType financialAccount = new FinancialAccountType();
					IDType financialAccountID = new IDType();
					financialAccountID.setValue(placanje.getRacun().getBrojRacuna());
					financialAccount.setID(financialAccountID);
					paymentMeans.setPayeeFinancialAccount(financialAccount);
				}
				invoice.getPaymentMeans().add(paymentMeans);
			}
			
			//uvjeti plaćanja - PaymentTerms			
			// NE POSTOJI PREMA "NOVOJ" SHEMI
			/*if(faktura.getUvjetiPlacanja()!=null && faktura.getUvjetiPlacanja().length()>0){
				PaymentTermsType paymentTerms = new PaymentTermsType();
				NoteType paymentTermsNote = new NoteType();
				paymentTermsNote.setValue(faktura.getUvjetiPlacanja()); // TODO uzeti iz objekta. napomena - polje u bazi još ne postoji
				paymentTerms.getNote().add(paymentTermsNote);
				invoice.setPaymentTerms(paymentTerms);
			}*/
			
			
			// OBRAČUN POREZA PO TIPOVIMA POREZA TaxTotal [0..*] (optional: total tax amounts for each tax type)
			class PorezGrupa {
				BigDecimal osnovica = BigDecimal.ZERO;
				BigDecimal iznos = BigDecimal.ZERO;
				BigDecimal stopa = null;
				String kategorija = null; // npr. "S" ili "O"
				String tip = null;    // npr. "VAT"
			}
			// Prikupi sve poreze iz svih stavki i sumiraj po stopi i tipu
			Map<String, PorezGrupa> rekap = new HashMap<>();
			for (FakturaStavkaModel stavka : faktura.getStavke()) {
				if (stavka.getPorezi() == null) continue;
				for (DokumentPorezModel porez : stavka.getPorezi()) {
					// Ključ može biti kombinacija stope i tipa ako imaš više tipova poreza
					String kljuc = porez.getStopa() + "|" + (porez.getTip() != null ? porez.getTip() : "");
					PorezGrupa pg = rekap.getOrDefault(kljuc, new PorezGrupa());
					pg.osnovica = pg.osnovica.add(porez.getOsnovica());
					pg.iznos = pg.iznos.add(porez.getIznos());
					pg.stopa = porez.getStopa();
					pg.kategorija = porez.getKategorija();
					pg.tip = porez.getTip();
					rekap.put(kljuc, pg);
				}
			}
			//mapiraj u Invoice
			BigDecimal ukupniPorez = BigDecimal.ZERO;
			String valuta = faktura.getValuta().getOznaka();
			TaxTotalType taxTotal = new TaxTotalType();			
			
			for (PorezGrupa pg : rekap.values()) {
				ukupniPorez = ukupniPorez.add(pg.iznos);
				
				TaxSubtotalType taxSubtotal = new TaxSubtotalType();
				
				TaxableAmountType taxableAmount = new TaxableAmountType();
				taxableAmount.setCurrencyID(valuta);
				taxableAmount.setValue(pg.osnovica.setScale(2, BigDecimal.ROUND_HALF_UP));
				taxSubtotal.setTaxableAmount(taxableAmount);
				
				TaxAmountType taxAmount = new TaxAmountType();
				taxAmount.setCurrencyID(valuta);
				taxAmount.setValue(pg.iznos.setScale(2, BigDecimal.ROUND_HALF_UP));
				taxSubtotal.setTaxAmount(taxAmount);
				
				TaxCategoryType taxCategory = new TaxCategoryType();
				IDType taxCategoryID = new IDType();
				taxCategoryID.setValue(pg.kategorija);
				taxCategory.setID(taxCategoryID);
				
				PercentType taxCategoryPercent = new PercentType();
				taxCategoryPercent.setValue(pg.stopa.setScale(0, BigDecimal.ROUND_HALF_UP));
				taxCategory.setPercent(taxCategoryPercent);
			
				TaxSchemeType taxScheme = new TaxSchemeType();
				IDType taxSchemeID = new IDType();
				taxSchemeID.setValue(pg.tip);
				taxScheme.setID(taxSchemeID);
				taxCategory.setTaxScheme(taxScheme);
			
				taxSubtotal.setTaxCategory(taxCategory);
				taxTotal.getTaxSubtotal().add(taxSubtotal);
			}
			TaxAmountType taxAmountSum = new TaxAmountType();
			taxAmountSum.setCurrencyID(valuta);
			taxAmountSum.setValue(ukupniPorez.setScale(2, BigDecimal.ROUND_HALF_UP));
			taxTotal.setTaxAmount(taxAmountSum);
			
			invoice.getTaxTotal().add(taxTotal);
			// GOTOV OBRAČUN POREZA			
			
			DokumentTotalModel total = DokumentTotalModel.dohvatiTotale(godina, faktura.getVrstaDokumenta(), faktura.getOnu().getId() ,faktura.getOnu().getOpp().getId(),faktura.getBroj(), conn);
			valuta = faktura.getValuta().getOznaka();
			
			MonetaryTotalType legalMonetaryTotal = new MonetaryTotalType();
			
			// LineExtensionAmount
			LineExtensionAmountType lineExtensionAmount = new LineExtensionAmountType();
			lineExtensionAmount.setValue(total.getLineExtensionAmount());
			lineExtensionAmount.setCurrencyID(valuta);
			legalMonetaryTotal.setLineExtensionAmount(lineExtensionAmount);
			
			// TaxExclusiveAmount
			TaxExclusiveAmountType taxExclusiveAmount = new TaxExclusiveAmountType();
			taxExclusiveAmount.setValue(total.getTaxExclusiveAmount());
			taxExclusiveAmount.setCurrencyID(valuta);
			legalMonetaryTotal.setTaxExclusiveAmount(taxExclusiveAmount);

			// TaxInclusiveAmount
			TaxInclusiveAmountType taxInclusiveAmount = new TaxInclusiveAmountType();
			taxInclusiveAmount.setValue(total.getTaxInclusiveAmount());
			taxInclusiveAmount.setCurrencyID(valuta);
			legalMonetaryTotal.setTaxInclusiveAmount(taxInclusiveAmount);

			// AllowanceTotalAmount
			AllowanceTotalAmountType allowanceTotalAmount = new AllowanceTotalAmountType();
			allowanceTotalAmount.setValue(total.getAllowanceTotalAmount());
			allowanceTotalAmount.setCurrencyID(valuta);
			legalMonetaryTotal.setAllowanceTotalAmount(allowanceTotalAmount);
			
			// ChargeTotalAmount
			ChargeTotalAmountType chargeTotalAmount = new ChargeTotalAmountType();
			chargeTotalAmount.setValue(total.getChargeTotalAmount());
			chargeTotalAmount.setCurrencyID(valuta);
			legalMonetaryTotal.setChargeTotalAmount(chargeTotalAmount);

			// PrepaidAmount
			PrepaidAmountType prepaidAmount = new PrepaidAmountType();
			prepaidAmount.setValue(total.getPrepaidAmount());
			prepaidAmount.setCurrencyID(valuta);
			legalMonetaryTotal.setPrepaidAmount(prepaidAmount);

			// PayableRoundingAmount (nije uvijek potreban, koristi samo ako ga zahtijeva UBL/projekt)
			if (total.getPayableRoundingAmount() != null) {
				PayableRoundingAmountType payableRoundingAmount = new PayableRoundingAmountType();
				payableRoundingAmount.setValue(total.getPayableRoundingAmount());
				payableRoundingAmount.setCurrencyID(valuta);
				legalMonetaryTotal.setPayableRoundingAmount(payableRoundingAmount);
			}

			// PayableAmount
			PayableAmountType payableAmount = new PayableAmountType();
			payableAmount.setValue(total.getPayableAmount());
			payableAmount.setCurrencyID(valuta);
			legalMonetaryTotal.setPayableAmount(payableAmount);
				
			// Dodaj u račun
			invoice.setLegalMonetaryTotal(legalMonetaryTotal);
			// GOTOVI TOTALI
		} catch (SQLException ex) {
				logger.error(new Functions().logging(ex));
		} finally {		
			if (defaultConnection.length == 0) {
				try {
					conn.close();
				} catch (SQLException ex) {
					logger.error(new Functions().logging(ex));
				}
			}
		}
	}
	
	public static void popuniStranke(InvoiceType invoice, FakturaModel faktura) {
		Stage stage = new Stage();
        // === DOBAVLJAČ (Supplier) ===
		int firmaId = DbFunctions.getMaxIdSifrarnika("podaci_firma");
		PodaciFirmaModel dobavljac = new PodaciFirmaModel();
		dobavljac.load(firmaId, stage,  false);
				
        SupplierPartyType supplierParty = new SupplierPartyType();
		PartyType dobavljacParty = new PartyType();
		supplierParty.setParty(dobavljacParty);

        supplierParty.getParty().setEndpointID(createEndpointID(dobavljac.getOib(), "9934"));
        //supplierParty.getParty().getPartyIdentification().add(createPartyIdentification(dobavljac.getOib(), "9934"));
		supplierParty.getParty().getPartyIdentification().add(createPartyIdentification("9934:" + dobavljac.getOib(), null));
        supplierParty.getParty().getPartyName().add(createPartyName(dobavljac.getNaziv()));
        supplierParty.getParty().setPostalAddress(createAddress(dobavljac.getAdresa() + " " + dobavljac.getKucniBroj() + dobavljac.getKucniBrojDodatak(),
																dobavljac.getMjesto(),dobavljac.getBrojPoste(), "HR")); // createAddress("Primorska 1", "Zagreb", "10000", "HR") 
        supplierParty.getParty().getPartyTaxScheme().add(createPartyTaxScheme("HR" + dobavljac.getOib()));
		supplierParty.getParty().getPartyLegalEntity().add(createLegalEntity(dobavljac.getNaziv(), dobavljac.getOib()));

        ContactType contact = new ContactType();
		IDType contactID = new IDType();
		contactID.setValue(faktura.getOib_operatera());
        NameType contactName = new NameType();
		contactName.setValue(KorisnikModel.fromOib(faktura.getOib_operatera(), stage, true).getOznakaOperatera());        
        contact.setID(contactID);
		contact.setName(contactName);
		
		SupplierPartyType accountingSupplier = new SupplierPartyType();		
		accountingSupplier.setSellerContact(contact);
        accountingSupplier.setParty(supplierParty.getParty());
        invoice.setAccountingSupplierParty(accountingSupplier);

        // === KUPAC (Customer) ===
        CustomerPartyType customerParty = new CustomerPartyType();
		PartyType kupacParty = new PartyType();
		
		// email adresa - možda privremeno - MER za sada traži kao obavezno
		contact = new ContactType();
		ElectronicMailType email = new ElectronicMailType();
		email.setValue("port@port.com.hr");        
        contact.setElectronicMail(email);		
		kupacParty.setContact(contact);
		
		customerParty.setParty(kupacParty);

        customerParty.getParty().setEndpointID(createEndpointID(faktura.getPartner().getOib(), "9934"));  // TODO ako kupac ima GLN tada ovdje promijeniti (9934 je id sheme za hrvatski oib)        
		customerParty.getParty().getPartyIdentification().add(createPartyIdentification("9934:" + faktura.getPartner().getOib(), null));
		
        customerParty.getParty().getPartyName().add(createPartyName(faktura.getPartner().getNaziv()));
		customerParty.getParty().setPostalAddress(createAddress(faktura.getPartner().getAdresa() + " " + faktura.getPartner().getKucniBroj() + dobavljac.getKucniBrojDodatak(),
																faktura.getPartner().getMjesto(),faktura.getPartner().getBrojPoste(), "HR"));
        
		if(faktura.getPartner().getOib()!=null && faktura.getPartner().getOib().length()>0){
			customerParty.getParty().getPartyTaxScheme().add(createPartyTaxScheme("HR" + faktura.getPartner().getOib()));        
			customerParty.getParty().getPartyLegalEntity().add(createLegalEntity(faktura.getPartner().getNaziv(),faktura.getPartner().getOib()));
		}else{ //kupac nema oib, uzmi porezni broj
			customerParty.getParty().getPartyTaxScheme().add(createPartyTaxScheme(faktura.getPartner().getPorezniBroj()));        
			customerParty.getParty().getPartyLegalEntity().add(createLegalEntity(faktura.getPartner().getNaziv(),faktura.getPartner().getPorezniBroj()));
		}
		
		
		
		
        CustomerPartyType accountingCustomer = new CustomerPartyType();
        accountingCustomer.setParty(customerParty.getParty());		
        invoice.setAccountingCustomerParty(accountingCustomer);
    }

    private static EndpointIDType createEndpointID(String value, String schemeID) {
        EndpointIDType id = new EndpointIDType();
        id.setValue(value);
        id.setSchemeID(schemeID);
        return id;
    }

    private static PartyIdentificationType createPartyIdentification(String value, String schemeID) {
        PartyIdentificationType ident = new PartyIdentificationType();
        IDType id = new IDType();
        id.setValue(value);
        id.setSchemeID(schemeID);
        ident.setID(id);
        return ident;
    }

    private static PartyNameType createPartyName(String name) {
        PartyNameType partyName = new PartyNameType();
        NameType nameType = new NameType();
        nameType.setValue(name);
        partyName.setName(nameType);
        return partyName;
    }

    private static AddressType createAddress(String street, String city, String postal, String countryCode) {
        AddressType address = new AddressType();

        StreetNameType streetName = new StreetNameType();
        streetName.setValue(street);
        address.setStreetName(streetName);

        CityNameType cityName = new CityNameType();
        cityName.setValue(city);
        address.setCityName(cityName);

        PostalZoneType postalZone = new PostalZoneType();
        postalZone.setValue(postal);
        address.setPostalZone(postalZone);

        CountryType country = new CountryType();
        IdentificationCodeType code = new IdentificationCodeType();
        code.setValue(countryCode);
        country.setIdentificationCode(code);
        address.setCountry(country);

        return address;
    }

    private static PartyTaxSchemeType createPartyTaxScheme(String companyID) {
        PartyTaxSchemeType tax = new PartyTaxSchemeType();

        CompanyIDType compId = new CompanyIDType();
        compId.setValue(companyID);
        tax.setCompanyID(compId);

        TaxSchemeType taxScheme = new TaxSchemeType();
        IDType taxSchemeId = new IDType();
        taxSchemeId.setValue("VAT");
		taxScheme.setID(taxSchemeId);
		tax.setTaxScheme(taxScheme); 
		
		System.out.println("TaxScheme: " + tax.getTaxScheme());
		System.out.println("TaxScheme.ID: " + tax.getTaxScheme().getID().getValue());
		
        return tax;
    }   

    private static PartyLegalEntityType createLegalEntity(String name, String companyID) {
        PartyLegalEntityType legal = new PartyLegalEntityType();

        RegistrationNameType regName = new RegistrationNameType();
        regName.setValue(name);
        legal.setRegistrationName(regName);

        CompanyIDType compId = new CompanyIDType();
        compId.setValue(companyID);
        legal.setCompanyID(compId);

        return legal;
    }	
	
	public static void popuniStavke(InvoiceType invoice, FakturaModel faktura) {
		
		// === ZA SVAKU STAVKU RAČUNA ===
		for(FakturaStavkaModel fakturaStavka: faktura.getStavke()){	
		
			InvoiceLineType stavka = new InvoiceLineType();
			
			// ID
			IDType id = new IDType();
			id.setValue(String.valueOf(fakturaStavka.getRbStavke()));
			stavka.setID(id);
			
			// Količina
			InvoicedQuantityType kolicina = new InvoicedQuantityType();
			kolicina.setUnitCode(fakturaStavka.getArtikl().getJedinica());
			kolicina.setValue(new BigDecimal(fakturaStavka.getKolicina()).setScale(4, BigDecimal.ROUND_HALF_UP));
			stavka.setInvoicedQuantity(kolicina);
			
			// Iznos linije (bez PDV-a)
			LineExtensionAmountType linijskiIznos = new LineExtensionAmountType();
			linijskiIznos.setCurrencyID(faktura.getValuta().getOznaka());
			System.out.println("stavka lineextension:" + fakturaStavka.getIznos() );
			linijskiIznos.setValue(fakturaStavka.getIznos().setScale(2, BigDecimal.ROUND_HALF_UP));
			stavka.setLineExtensionAmount(linijskiIznos);
			
			// Popust ili trošak na razini stavke			
			if (fakturaStavka.getPopustiTroskovi() != null) {	//radi čvorove samo ako postoje popusti/troškovi
				for (PopustTrosakModel popTros : fakturaStavka.getPopustiTroskovi()) {
					if(popTros.getStopa()!=null && popTros.getStopa().compareTo(BigDecimal.ZERO)>0){ // ako je zadana stopa i ako je ona veća od nule
						AllowanceChargeType allowanceCharge = new AllowanceChargeType();
						ChargeIndicatorType chargeIndicator = new ChargeIndicatorType();
						chargeIndicator.setValue(popTros.isTrosak());  // TRUE = trošak, FALSE = popust
						allowanceCharge.setChargeIndicator(chargeIndicator);
					
						if(popTros.isTrosak() && (popTros.getRazlog() == null || popTros.getRazlog().length() == 0)) popTros.setRazlog("trošak");
						if(!popTros.isTrosak() && (popTros.getRazlog() == null || popTros.getRazlog().length() == 0)) popTros.setRazlog("popust");					
						AllowanceChargeReasonType allowanceChargeReason = new AllowanceChargeReasonType();
						allowanceChargeReason.setValue(popTros.getRazlog()); // razlog popuštanja ili troška
						allowanceCharge.getAllowanceChargeReason().add(allowanceChargeReason);
		
						if (popTros.getStopa() != null) {
							MultiplierFactorNumericType multiplierFactor = new MultiplierFactorNumericType();
							multiplierFactor.setValue(popTros.getStopa().divide(BigDecimal.valueOf(100))); // upisuje se koeficijent, a ne stopa
							allowanceCharge.setMultiplierFactorNumeric(multiplierFactor);
						}
			
						AmountType amount = new AmountType();
						amount.setCurrencyID(faktura.getValuta().getOznaka());
						amount.setValue(popTros.getIznos());
						allowanceCharge.setAmount(amount);
			
						if (popTros.getOsnovica() != null) {					
							BaseAmountType baseAmount = new BaseAmountType();
							baseAmount.setCurrencyID(faktura.getValuta().getOznaka()); // TODO
							baseAmount.setValue(popTros.getOsnovica());
							allowanceCharge.setBaseAmount(baseAmount);
						}
		
						stavka.getAllowanceCharge().add(allowanceCharge);
					}
				}
			}			
			//GOTOV POPUST/TROŠAK
			
			// === Artikl - ITEM ===
			ItemType item = new ItemType();			
			NameType naziv = new NameType();
			naziv.setValue(fakturaStavka.getArtikl().getNaziv());
			item.setName(naziv);
			
			CommodityClassificationType commodity = new CommodityClassificationType();
			ItemClassificationCodeType kpd = new ItemClassificationCodeType();
			kpd.setListID("CG");
			kpd.setValue(fakturaStavka.getArtikl().getKpd().getCode());
			commodity.setItemClassificationCode(kpd);
			item.getCommodityClassification().add(commodity);			
			
			//ItemIdentificationType sifra = new ItemIdentificationType();
			//IDType sifraId = new IDType();
			//sifraId.setValue(fakturaStavka.getArtikl().getSifra());
			//sifra.setID(sifraId);
			//item.setSellersItemIdentification(sifra);						
			
			// POREZI STAVKE - ITEM-a
			if (fakturaStavka.getPorezi() != null) { //radi ramo ako su dodani porez(i) na stavku
				for (DokumentPorezModel porez : fakturaStavka.getPorezi()) {				
					TaxCategoryType classifiedTaxCategory = new TaxCategoryType();
					IDType taxCategoryId = new IDType();
					taxCategoryId.setValue(porez.getKategorija());
					classifiedTaxCategory.setID(taxCategoryId);
					
					PercentType taxPercent = new PercentType();
					taxPercent.setValue(porez.getStopa().setScale(2, BigDecimal.ROUND_HALF_UP));
					classifiedTaxCategory.setPercent(taxPercent);
					
					TaxSchemeType taxScheme = new TaxSchemeType();
					IDType taxSchemeId = new IDType();
					taxSchemeId.setValue(porez.getTip()); //  TODO uzeti iz stavke kad se promijeni šema poreza u programu
					taxScheme.setID(taxSchemeId);
					classifiedTaxCategory.setTaxScheme(taxScheme);			
					
					item.getClassifiedTaxCategory().add(classifiedTaxCategory);
				}
			}
			stavka.setItem(item);
			
			// === Cijena ===
			PriceType cijena = new PriceType();
			PriceAmountType cijenaIznos = new PriceAmountType();
			cijenaIznos.setCurrencyID(faktura.getValuta().getOznaka());
			cijenaIznos.setValue(new BigDecimal(fakturaStavka.getCijena()).setScale(2, BigDecimal.ROUND_HALF_UP));
			cijena.setPriceAmount(cijenaIznos);
			
			BaseQuantityType baseQuantity = new BaseQuantityType();
			baseQuantity.setUnitCode(fakturaStavka.getArtikl().getJedinica());
			baseQuantity.setValue(new BigDecimal(fakturaStavka.getKolicina()).setScale(2, BigDecimal.ROUND_HALF_UP));
			cijena.setBaseQuantity(baseQuantity);
						
			stavka.setPrice(cijena);
			
			// Dodaj stavku
			invoice.getInvoiceLine().add(stavka);
		}
	}
}