<?php

namespace App\Providers;

use App\Models\SepaPaymentElement;
use DOMDocument;
use Exception;

class PainFileProvider {
    public string $senderIban;
    public string $senderName;
    public string $senderBic;

    /** @var SepaPaymentElement[] */
    public array $elements;

    public function __construct(string $senderIban, string $senderName, string $senderBic, array $elements) {
        $this->senderIban = $senderIban;
        $this->senderName = $senderName;
        $this->senderBic = $senderBic;
        $this->elements = $elements;
    }

    public function createPainFileContent() : string {
        $doc = new DOMDocument('1.0', 'UTF-8');
        $doc->formatOutput = true;

        $senderIban = str_replace(' ', '', $this->senderIban);
        $senderBic = str_replace(' ', '', $this->senderBic);

        // Root-Element
        $document = $doc->createElement('Document');
        $document->setAttribute('xmlns', 'urn:iso:std:iso:20022:tech:xsd:pain.001.001.03');
        $document->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
        $doc->appendChild($document);

        // CstmrCdtTrfInitn
        $cstmr_cdt_trf_initn = $doc->createElement('CstmrCdtTrfInitn');
        $document->appendChild($cstmr_cdt_trf_initn);

        // GrpHdr
        $grp_hdr = $doc->createElement('GrpHdr');
        $cstmr_cdt_trf_initn->appendChild($grp_hdr);

        $grp_hdr->appendChild($doc->createElement('MsgId', uniqid('MSG')));
        $grp_hdr->appendChild($doc->createElement('CreDtTm', date('c')));
        $grp_hdr->appendChild($doc->createElement('NbOfTxs', count($this->elements)));

        $totalAmount = array_sum(array_map(fn(SepaPaymentElement $e) => $e->amount, $this->elements));
        $grp_hdr->appendChild($doc->createElement('CtrlSum', number_format($totalAmount, 2, '.', '')));

        $initg_pty = $doc->createElement('InitgPty');
        $initg_pty->appendChild($doc->createElement('Nm', $this->senderName));
        $grp_hdr->appendChild($initg_pty);

        // PmtInf
        $pmt_inf = $doc->createElement('PmtInf');
        $cstmr_cdt_trf_initn->appendChild($pmt_inf);

        $pmt_inf->appendChild($doc->createElement('PmtInfId', uniqid('PMT')));
        $pmt_inf->appendChild($doc->createElement('PmtMtd', 'TRF'));
        $pmt_inf->appendChild($doc->createElement('BtchBookg', 'false'));
        $pmt_inf->appendChild($doc->createElement('NbOfTxs', count($this->elements)));
        $pmt_inf->appendChild($doc->createElement('CtrlSum', number_format($totalAmount, 2, '.', '')));

        $pmt_tp_inf = $doc->createElement('PmtTpInf');
        $svc_lvl = $doc->createElement('SvcLvl');
        $svc_lvl->appendChild($doc->createElement('Cd', 'SEPA'));
        $pmt_tp_inf->appendChild($svc_lvl);
        $pmt_inf->appendChild($pmt_tp_inf);

        $pmt_inf->appendChild($doc->createElement('ReqdExctnDt', date('Y-m-d', mktime(0))));

        $dbtr = $doc->createElement('Dbtr');
        $dbtr->appendChild($doc->createElement('Nm', $this->senderName));
        $pmt_inf->appendChild($dbtr);

        $dbtr_acct = $doc->createElement('DbtrAcct');
        $id = $doc->createElement('Id');
        $id->appendChild($doc->createElement('IBAN', $senderIban));
        $dbtr_acct->appendChild($id);
        $pmt_inf->appendChild($dbtr_acct);


        $dbtr_agt = $doc->createElement('DbtrAgt');
        $id = $doc->createElement('FinInstnId');
        $id->appendChild($doc->createElement('BIC', $senderBic));
        $dbtr_agt->appendChild($id);
        $pmt_inf->appendChild($dbtr_agt);

        foreach ($this->elements as $index => $element) {
            $cdt_trf_tx_inf = $doc->createElement('CdtTrfTxInf');

            $pmt_id = $doc->createElement('PmtId');
            $pmt_id->appendChild($doc->createElement('EndToEndId', uniqid('ET')));
            $cdt_trf_tx_inf->appendChild($pmt_id);

            $amt = $doc->createElement('Amt');
            $instd_amt = $doc->createElement('InstdAmt', number_format($element->amount, 2, '.', ''));
            $instd_amt->setAttribute('Ccy', 'EUR');
            $amt->appendChild($instd_amt);
            $cdt_trf_tx_inf->appendChild($amt);

            $cdtr = $doc->createElement('Cdtr');
            $cdtr->appendChild($doc->createElement('Nm', $element->recipient_name));
            $cdt_trf_tx_inf->appendChild($cdtr);

            $cdtr_acct = $doc->createElement('CdtrAcct');
            $cdtr_id = $doc->createElement('Id');
            $cdtr_id->appendChild($doc->createElement('IBAN', str_replace(' ', '', $element->recipient_iban)));
            $cdtr_acct->appendChild($cdtr_id);
            $cdt_trf_tx_inf->appendChild($cdtr_acct);

            $rmt_inf = $doc->createElement('RmtInf');
            $rmt_inf->appendChild($doc->createElement('Ustrd', $element->payment_purpose));
            $cdt_trf_tx_inf->appendChild($rmt_inf);

            $pmt_inf->appendChild($cdt_trf_tx_inf);
        }

        $xml_content = $doc->saveXML();
        if (false === $xml_content) {
            throw new Exception('Failed to generate XML content.');
        }
        return $xml_content;
    }
}
