/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.ctecinf.nfe;

import br.com.ctecinf.Utils;
import br.com.ctecinf.text.MaskFormatter;
import br.com.ctecinf.text.NumberFormatter;
import br.com.ctecinf.text.TimestampFormatter;
import br.inf.portalfiscal.nfe.v400.autorizacao.TNFe;
import br.inf.portalfiscal.nfe.v400.autorizacao.TNfeProc;
import com.itextpdf.text.Image;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.BarcodeQRCode;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import java.io.File;
import java.io.FileOutputStream;
import java.io.StringReader;
import org.w3c.dom.Document;

/**
 *
 * @author Cássio Conceição
 * @since 06/11/2018
 * @version 201811
 * @see http://ctecinf.com.br/
 */
public class DanfePDF {

    /**
     * Cria um arquivo PDF da DANFE NFC-e
     *
     * @param xmlPath Caminho do XML
     * @return
     * @throws Exception
     */
    public static File createFile(String xmlPath) throws Exception {
        return createFile(new File(xmlPath));
    }

    /**
     * Cria um arquivo PDF da DANFE NFC-e
     *
     * @param xml Arquivo xml
     * @return
     * @throws Exception
     */
    public static File createFile(File xml) throws Exception {

        File pdf = new File("pdf", xml.getName().replace(".xml", ".pdf"));

        if (!pdf.getParentFile().exists()) {
            pdf.getParentFile().mkdirs();
        }

        if (pdf.exists()) {
            return pdf;
        }

        com.itextpdf.text.Document document = new com.itextpdf.text.Document();

        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(pdf));

        document.open();

        String strXML = Utils.readFile(xml);

        Object nfe;

        if (strXML.contains("versao=\"4.00\"")) {
            nfe = Utils.unmarshaller(TNfeProc.class, strXML);
        } else {
            nfe = Utils.unmarshaller(br.inf.portalfiscal.nfe.v310.autorizacao.TNfeProc.class, strXML);
        }

        String str = getDanfeHTML(nfe);
        System.out.println(str);
        XMLWorkerHelper.getInstance().parseXHtml(writer, document, new StringReader(str));

        BarcodeQRCode barcodeQRCode;

        if (nfe instanceof TNfeProc) {
            barcodeQRCode = new BarcodeQRCode(((TNfeProc) nfe).getNFe().getInfNFeSupl().getQrCode(), 1000, 1000, null);
        } else {
            barcodeQRCode = new BarcodeQRCode(((br.inf.portalfiscal.nfe.v310.autorizacao.TNfeProc) nfe).getNFe().getInfNFeSupl().getQrCode(), 1000, 1000, null);
        }

        Image codeQrImage = barcodeQRCode.getImage();
        codeQrImage.scaleAbsolute(120, 120);

        Paragraph p = new Paragraph();
        p.add(codeQrImage);
        p.setIndentationLeft(45);

        document.add(p);

        String desc;

        if (nfe instanceof TNfeProc) {
            desc = ((TNfeProc) nfe).getNFe().getInfNFe().getInfAdic().getInfCpl();
        } else {
            desc = ((br.inf.portalfiscal.nfe.v310.autorizacao.TNfeProc) nfe).getNFe().getInfNFe().getInfAdic().getInfCpl();
        }

        XMLWorkerHelper.getInstance().parseXHtml(writer, document, new StringReader("<div style=\"width:280px;font-size:9px\"><p align=\"center\">" + desc + "</p></div>"));

        document.close();

        return pdf;
    }

    private static String getDanfeHTML(Object nfe) {

        if (nfe instanceof TNfeProc) {
            return danfe4HTML((TNfeProc) nfe);
        } else {
            return danfe3((br.inf.portalfiscal.nfe.v310.autorizacao.TNfeProc) nfe);
        }
    }

    private static String head(Object nfe) {

        String cnpj;
        String razaoSocial;
        String endereco;

        if (nfe instanceof TNfeProc) {

            TNfeProc p = (TNfeProc) nfe;

            cnpj = p.getNFe().getInfNFe().getEmit().getCNPJ();
            razaoSocial = p.getNFe().getInfNFe().getEmit().getXNome();
            endereco = p.getNFe().getInfNFe().getEmit().getEnderEmit().getXLgr();
            endereco += p.getNFe().getInfNFe().getEmit().getEnderEmit().getNro() != null ? ", " + p.getNFe().getInfNFe().getEmit().getEnderEmit().getNro() : "";
            endereco += p.getNFe().getInfNFe().getEmit().getEnderEmit().getXCpl() != null ? " - " + p.getNFe().getInfNFe().getEmit().getEnderEmit().getXCpl() : "";
            endereco += p.getNFe().getInfNFe().getEmit().getEnderEmit().getXBairro() != null ? ", " + p.getNFe().getInfNFe().getEmit().getEnderEmit().getXBairro() : "";
            endereco += p.getNFe().getInfNFe().getEmit().getEnderEmit().getXMun() != null ? ", " + p.getNFe().getInfNFe().getEmit().getEnderEmit().getXMun() : "";
            endereco += " - " + p.getNFe().getInfNFe().getEmit().getEnderEmit().getUF().value();

        } else {

            br.inf.portalfiscal.nfe.v310.autorizacao.TNfeProc p = (br.inf.portalfiscal.nfe.v310.autorizacao.TNfeProc) nfe;

            cnpj = p.getNFe().getInfNFe().getEmit().getCNPJ();
            razaoSocial = p.getNFe().getInfNFe().getEmit().getXNome();
            endereco = p.getNFe().getInfNFe().getEmit().getEnderEmit().getXLgr();
            endereco += p.getNFe().getInfNFe().getEmit().getEnderEmit().getNro() != null ? ", " + p.getNFe().getInfNFe().getEmit().getEnderEmit().getNro() : "";
            endereco += p.getNFe().getInfNFe().getEmit().getEnderEmit().getXCpl() != null ? " - " + p.getNFe().getInfNFe().getEmit().getEnderEmit().getXCpl() : "";
            endereco += p.getNFe().getInfNFe().getEmit().getEnderEmit().getXBairro() != null ? ", " + p.getNFe().getInfNFe().getEmit().getEnderEmit().getXBairro() : "";
            endereco += p.getNFe().getInfNFe().getEmit().getEnderEmit().getXMun() != null ? ", " + p.getNFe().getInfNFe().getEmit().getEnderEmit().getXMun() : "";
            endereco += " - " + p.getNFe().getInfNFe().getEmit().getEnderEmit().getUF().value();
        }

        return "                <p align=\"center\">CNPJ " + MaskFormatter.format(cnpj, "##.###.###/####-##") + " <b>" + razaoSocial + "</b><br />\n"
                + "                " + endereco + "<br />\n"
                + "                Documento Auxiliar da Nota Fiscal de Consumidor Eletrônica</p><br />\n";
    }

    private static String produtos(Object nfe) {

        String cod;
        String desc;
        String qtde;
        String und;
        String vlUnit;
        String total;

        String str = "";

        if (nfe instanceof TNfeProc) {

            TNfeProc p = (TNfeProc) nfe;

            for (TNFe.InfNFe.Det det : p.getNFe().getInfNFe().getDet()) {

                TNFe.InfNFe.Det.Prod prod = det.getProd();

                cod = prod.getCProd();
                desc = prod.getXProd();
                qtde = prod.getQCom();
                und = prod.getUCom();
                vlUnit = NumberFormatter.format().format(Double.parseDouble(prod.getVUnCom()));
                total = NumberFormatter.format().format(Double.parseDouble(prod.getVProd()));

                str += "                <tr>\n"
                        + "                    <td>" + cod + "</td><td>" + desc + "</td><td>" + qtde + "</td><td>" + und + "</td><td align=\"right\">" + vlUnit + "</td><td align=\"right\">" + total + "</td>\n"
                        + "                </tr>\n";
            }

        } else {

            br.inf.portalfiscal.nfe.v310.autorizacao.TNfeProc p = (br.inf.portalfiscal.nfe.v310.autorizacao.TNfeProc) nfe;

            for (br.inf.portalfiscal.nfe.v310.autorizacao.TNFe.InfNFe.Det det : p.getNFe().getInfNFe().getDet()) {

                br.inf.portalfiscal.nfe.v310.autorizacao.TNFe.InfNFe.Det.Prod prod = det.getProd();

                cod = prod.getCProd();
                desc = prod.getXProd();
                qtde = prod.getQCom();
                und = prod.getUCom();
                vlUnit = NumberFormatter.format().format(Double.parseDouble(prod.getVUnCom()));
                total = NumberFormatter.format().format(Double.parseDouble(prod.getVProd()));

                str += "                <tr>\n"
                        + "                    <td>" + cod + "</td><td>" + desc + "</td><td>" + qtde + "</td><td>" + und + "</td><td align=\"right\">" + vlUnit + "</td><td align=\"right\">" + total + "</td>\n"
                        + "                </tr>\n";
            }
        }

        return str;
    }

    private static String pagamentos(Object nfe) {

        String desc;
        String valor;

        String str = "";

        if (nfe instanceof TNfeProc) {

            TNfeProc p = (TNfeProc) nfe;

            for (TNFe.InfNFe.Pag.DetPag detPag : p.getNFe().getInfNFe().getPag().getDetPag()) {

                desc = getDescPagto(detPag.getTPag());

                valor = NumberFormatter.format().format(Double.parseDouble(detPag.getVPag()));

                str += "                <tr>\n"
                        + "                    <td align=\"left\">" + desc + "</td><td align=\"right\">" + valor + "</td>\n"
                        + "                </tr>\n";
            }

        } else {

            br.inf.portalfiscal.nfe.v310.autorizacao.TNfeProc p = (br.inf.portalfiscal.nfe.v310.autorizacao.TNfeProc) nfe;

            for (br.inf.portalfiscal.nfe.v310.autorizacao.TNFe.InfNFe.Pag pag : p.getNFe().getInfNFe().getPag()) {

                desc = getDescPagto(pag.getTPag());

                valor = NumberFormatter.format().format(Double.parseDouble(pag.getVPag()));

                str += "                <tr>\n"
                        + "                    <td align=\"left\">" + desc + "</td><td align=\"right\">" + valor + "</td>\n"
                        + "                </tr>\n";
            }
        }

        return str;
    }

    private static String getDescPagto(String tPag) {

        return switch (tPag) {
            case "01" ->
                "Dinheiro";
            case "02" ->
                "Cheque";
            case "03" ->
                "Cartao de Credito";
            case "04" ->
                "Cartao de Debito";
            case "05" ->
                "Credito Loja";
            case "16" ->
                "Deposito Bancario";
            case "17" ->
                "Pagamento Instantaneo (Pix)";
            default ->
                "Outros";
        };
    }

    private static String danfe3(br.inf.portalfiscal.nfe.v310.autorizacao.TNfeProc nfe) {

        String str = "<div style=\"width:320px;font-size:9px\">\n"
                + "            \n"
                + head(nfe)
                + "            \n"
                + "            <table style=\"width:100%;font-size:8px\">\n"
                + "                <tr>\n"
                + "                    <th width=\"10%\" align=\"left\">Cód.</th><th width=\"40%\" align=\"left\">Descrição</th><th width=\"10%\" align=\"left\">Qtde.</th><th width=\"10%\" align=\"left\">UN</th><th width=\"15%\" align=\"right\">Vl. Unit.</th><th width=\"15%\" align=\"right\">Vl. Total</th>\n"
                + "                </tr>\n"
                + produtos(nfe)
                + "            </table>\n"
                + "            \n"
                + "            <table style=\"width:100%;font-size:9px\">\n"
                + "                \n"
                + "                <tr>\n"
                + "                    <td align=\"left\">Qtde. total de itens</td><td align=\"right\">" + nfe.getNFe().getInfNFe().getDet().size() + "</td>\n"
                + "                </tr>\n"
                + "                \n"
                + "                <tr>\n"
                + "                    <td align=\"left\">Valor total R$</td><td align=\"right\">" + NumberFormatter.format().format(Double.parseDouble(nfe.getNFe().getInfNFe().getTotal().getICMSTot().getVProd())) + "</td>\n"
                + "                </tr>\n"
                + "                \n"
                + "                <tr>\n"
                + "                    <td align=\"left\">Desconto R$</td><td align=\"right\">" + NumberFormatter.format().format(Double.parseDouble(nfe.getNFe().getInfNFe().getTotal().getICMSTot().getVDesc())) + "</td>\n"
                + "                </tr>\n"
                + "                \n"
                + "                <tr>\n"
                + "                    <th align=\"left\">Valor à pagar R$</th><th align=\"right\">" + NumberFormatter.format().format(Double.parseDouble(nfe.getNFe().getInfNFe().getTotal().getICMSTot().getVNF())) + "</th>\n"
                + "                </tr>\n"
                + "                \n"
                + "            </table>\n"
                + "            \n"
                + "            <table style=\"width:100%;font-size:9px\">\n"
                + "                \n"
                + "                <tr>\n"
                + "                    <td align=\"left\">FORMA PAGAMENTO</td><td align=\"right\">VALOR PAGO R$</td>\n"
                + "                </tr>\n"
                + "                \n"
                + pagamentos(nfe)
                + "                \n"
                + "            </table>\n"
                + "            \n"
                + "            <p align=\"center\"><b>Consulte pela chave de acesso em</b><br />https://www.sefaz.rs.gov.br/NFCE/NFCE-COM.aspx<br />" + MaskFormatter.format(nfe.getNFe().getInfNFe().getId().replace("NFe", ""), "#### #### #### #### #### #### #### #### #### #### ####") + "</p>\n"
                + "            \n";

        if (nfe.getNFe().getInfNFe().getDest() != null) {

            String nome = nfe.getNFe().getInfNFe().getDest().getXNome();

            if (nfe.getNFe().getInfNFe().getDest().getCPF() != null) {

                String cpf = nfe.getNFe().getInfNFe().getDest().getCPF();

                str += "<p align=\"center\"><b>CONSUMIDOR - CPF " + MaskFormatter.format(cpf, "###.###.###-##") + "</b>";

            } else if (nfe.getNFe().getInfNFe().getDest().getIdEstrangeiro() != null) {

                String idEstrangeiro = nfe.getNFe().getInfNFe().getDest().getCPF();

                str += "<p align=\"center\"><b>CONSUMIDOR - ID ESTRANGEIRO " + idEstrangeiro + "</b>";
            }

            if (!nome.isEmpty()) {
                str += "<br />" + nome;
            }

            str += "</p>";

        } else {
            str += "<p align=\"center\"><b>CONSUMIDOR NÃO IDENTIFICADO</b></p>";
        }

        str += "            \n"
                + "            <p align=\"center\"><b>NFC-e " + nfe.getNFe().getInfNFe().getIde().getNNF() + "&nbsp;&nbsp;&nbsp;Série " + nfe.getNFe().getInfNFe().getIde().getSerie() + "&nbsp;&nbsp;&nbsp;" + TimestampFormatter.format().format(Utils.dateNFe2Date(nfe.getNFe().getInfNFe().getIde().getDhEmi()).getTime()) + "<br />Protocolo de autorização:</b> " + MaskFormatter.format(nfe.getProtNFe().getInfProt().getNProt(), "### ########## ##") + "<br /><b>Data de autorização</b> " + TimestampFormatter.format().format(Utils.dateNFe2Date(nfe.getProtNFe().getInfProt().getDhRecbto()).getTime()) + "</p>\n"
                + "            \n"
                + "        </div>";

        return str;
    }

    private static String danfe4HTML(TNfeProc nfe) {

        String str = "<div style=\"width:320px;font-size:9px\">\n"
                + "            \n"
                + head(nfe)
                + "            \n"
                + "            <table style=\"width:100%;font-size:8px\">\n"
                + "                <tr>\n"
                + "                    <th width=\"10%\" align=\"left\">Cód.</th><th width=\"40%\" align=\"left\">Descrição</th><th width=\"10%\" align=\"left\">Qtde.</th><th width=\"10%\" align=\"left\">UN</th><th width=\"15%\" align=\"right\">Vl. Unit.</th><th width=\"15%\" align=\"right\">Vl. Total</th>\n"
                + "                </tr>\n"
                + produtos(nfe)
                + "            </table>\n"
                + "            \n"
                + "            <table style=\"width:100%;font-size:9px\">\n"
                + "                \n"
                + "                <tr>\n"
                + "                    <td align=\"left\">Qtde. total de itens</td><td align=\"right\">" + nfe.getNFe().getInfNFe().getDet().size() + "</td>\n"
                + "                </tr>\n"
                + "                \n"
                + "                <tr>\n"
                + "                    <td align=\"left\">Valor total R$</td><td align=\"right\">" + NumberFormatter.format().format(Double.parseDouble(nfe.getNFe().getInfNFe().getTotal().getICMSTot().getVProd())) + "</td>\n"
                + "                </tr>\n"
                + "                \n"
                + "                <tr>\n"
                + "                    <td align=\"left\">Desconto R$</td><td align=\"right\">" + NumberFormatter.format().format(Double.parseDouble(nfe.getNFe().getInfNFe().getTotal().getICMSTot().getVDesc())) + "</td>\n"
                + "                </tr>\n"
                + "                \n"
                + "                <tr>\n"
                + "                    <th align=\"left\">Valor à pagar R$</th><th align=\"right\">" + NumberFormatter.format().format(Double.parseDouble(nfe.getNFe().getInfNFe().getTotal().getICMSTot().getVNF())) + "</th>\n"
                + "                </tr>\n"
                + "                \n"
                + "            </table>\n"
                + "            \n"
                + "            <table style=\"width:100%;font-size:9px\">\n"
                + "                \n"
                + "                <tr>\n"
                + "                    <td align=\"left\">FORMA PAGAMENTO</td><td align=\"right\">VALOR PAGO R$</td>\n"
                + "                </tr>\n"
                + "                \n"
                + pagamentos(nfe)
                + "                \n"
                + "            </table>\n"
                + "            \n"
                + "            <table style=\"width:100%;font-size:9px\">\n"
                + "                \n"
                + "                <tr>\n"
                + "                    <td align=\"left\">Troco R$</td><td align=\"right\">" + NumberFormatter.format().format(nfe.getNFe().getInfNFe().getPag().getVTroco() == null ? "0" : Double.parseDouble(nfe.getNFe().getInfNFe().getPag().getVTroco())) + "</td>\n"
                + "                </tr>\n"
                + "                \n"
                + "            </table>\n"
                + "            \n"
                + "            <p align=\"center\"><b>Consulte pela chave de acesso em</b><br />https://www.sefaz.rs.gov.br/NFCE/NFCE-COM.aspx<br />" + MaskFormatter.format(nfe.getNFe().getInfNFe().getId().replace("NFe", ""), "#### #### #### #### #### #### #### #### #### #### ####") + "</p>\n"
                + "            \n";

        if (nfe.getNFe().getInfNFe().getDest() != null) {

            String nome = nfe.getNFe().getInfNFe().getDest().getXNome();

            if (nfe.getNFe().getInfNFe().getDest().getCPF() != null) {

                String cpf = nfe.getNFe().getInfNFe().getDest().getCPF();

                str += "<p align=\"center\"><b>CONSUMIDOR - CPF " + MaskFormatter.format(cpf, "###.###.###-##") + "</b>";

            } else if (nfe.getNFe().getInfNFe().getDest().getIdEstrangeiro() != null) {

                String idEstrangeiro = nfe.getNFe().getInfNFe().getDest().getCPF();

                str += "<p align=\"center\"><b>CONSUMIDOR - ID ESTRANGEIRO " + idEstrangeiro + "</b>";
            }

            if (nome != null && !nome.isEmpty()) {
                str += "<br />" + nome;
            }

            str += "</p>";

        } else {
            str += "<p align=\"center\"><b>CONSUMIDOR NÃO IDENTIFICADO</b></p>";
        }

        str += "            \n"
                + "            <p align=\"center\"><b>NFC-e " + nfe.getNFe().getInfNFe().getIde().getNNF() + "&nbsp;&nbsp;&nbsp;Série " + nfe.getNFe().getInfNFe().getIde().getSerie() + "&nbsp;&nbsp;&nbsp;" + TimestampFormatter.format().format(Utils.dateNFe2Date(nfe.getNFe().getInfNFe().getIde().getDhEmi()).getTime()) + "<br />Protocolo de autorização:</b> " + MaskFormatter.format(nfe.getProtNFe().getInfProt().getNProt(), "### ########## ##") + "<br /><b>Data de autorização</b> " + TimestampFormatter.format().format(Utils.dateNFe2Date(nfe.getProtNFe().getInfProt().getDhRecbto()).getTime()) + "</p>\n"
                + "            \n"
                + "        </div>";
        return str;
    }

}
