using Elwig.Helpers.Billing;
using Elwig.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace Elwig.Helpers.Export {
    public class Ebics : IBankingExporter {

        public static string FileExtension => "xml";

        private readonly StreamWriter _writer;
        private readonly DateOnly _date;
        private readonly int _year;
        private readonly string _name;
        private readonly int _nr;

        public Ebics(PaymentVar variant, string filename) {
            _writer = new(filename, false, Utils.UTF8);
            _date = variant.TransferDate ?? DateOnly.Parse("2021-01-10"); //throw new ArgumentException("TransferDate has to be set in PaymentVar");
            _year = variant.Year;
            _name = variant.Name;
            _nr = variant.AvNr;
        }

        public void Dispose() {
            GC.SuppressFinalize(this);
            _writer.Dispose();
        }

        public ValueTask DisposeAsync() {
            GC.SuppressFinalize(this);
            return _writer.DisposeAsync();
        }

        public void Export(IEnumerable<Transaction> transactions, IProgress<double>? progress = null) {
            ExportAsync(transactions, progress).GetAwaiter().GetResult();
        }

        public async Task ExportAsync(IEnumerable<Transaction> transactions, IProgress<double>? progress = null) {
            progress?.Report(0.0);
            var nbOfTxs = transactions.Count();
            int count = nbOfTxs + 2, i = 0;
            var ctrlSum = Transaction.FormatAmountCent(transactions.Sum(tx => tx.AmountCent));
            var msgId = $"ELWIG-{App.Client.NameToken}-{_year}-AV{_nr:00}";
            var pmtInfId = $"{msgId}-1";

            await _writer.WriteLineAsync($"""
                <?xml version="1.0" encoding="UTF-8"?>
                <Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.09"
                          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                          xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:pain.001.001.09 pain.001.001.09.xsd">
                  <CstmrCdtTrfInitn>
                    <GrpHdr>
                      <MsgId>{msgId}</MsgId>
                      <CreDtTm>{DateTime.UtcNow:o}</CreDtTm>
                      <NbOfTxs>{nbOfTxs}</NbOfTxs>
                      <CtrlSum>{ctrlSum}</CtrlSum>
                      <InitgPty><Nm>{App.Client.NameFull}</Nm></InitgPty>
                    </GrpHdr>
                    <PmtInf>
                      <PmtInfId>{pmtInfId}</PmtInfId>
                      <PmtMtd>TRF</PmtMtd>
                      <NbOfTxs>{nbOfTxs}</NbOfTxs>
                      <CtrlSum>{ctrlSum}</CtrlSum>
                      <ReqdExctnDt><Dt>{_date:yyyy-MM-dd}</Dt></ReqdExctnDt>
                      <Dbtr><Nm>{App.Client.NameFull}</Nm></Dbtr>
                      <DbtrAcct><Id><IBAN>{App.Client.Iban?.Replace(" ", "")}</IBAN></Id></DbtrAcct>
                      <DbtrAgt><FinInstnId><BICFI>{App.Client.Bic ?? "NOTPROVIDED"}</BICFI></FinInstnId></DbtrAgt>
                """);
            progress?.Report(100.0 * ++i / count);

            foreach (var tx in transactions) {
                var a = (IAddress?)tx.Member.BillingAddress ?? tx.Member;
                var (a1, a2) = Utils.SplitAddress(a.Address);
                var id = $"ELWIG-{App.Client.NameToken}-{_year}-TG{tx.Nr:0000}";
                var info = $"{_name} - Traubengutschrift {_year}/{tx.Nr:000}";
                await _writer.WriteLineAsync($"""
                          <CdtTrfTxInf>
                            <PmtId><EndToEndId>{id}</EndToEndId></PmtId>
                            <Amt><InstdAmt Ccy="{tx.Currency}">{Transaction.FormatAmountCent(tx.AmountCent)}</InstdAmt></Amt>
                            <Cdtr>
                              <Nm>{a.Name}</Nm>
                              <PstlAdr>
                                <StrtNm>{a1}</StrtNm><BldgNb>{a2}</BldgNb>
                                <PstCd>{a.PostalDest.AtPlz?.Plz}</PstCd><TwnNm>{a.PostalDest.AtPlz?.Ort.Name}</TwnNm>
                                <Ctry>{a.PostalDest.Country.Alpha2}</Ctry>
                              </PstlAdr>
                            </Cdtr>
                            <CdtrAcct><Id><IBAN>{tx.Member.Iban}</IBAN></Id><CdtrAcct>
                            <CdtrAgt><FinInstnId><BICFI>{tx.Member.Bic ?? "NOTPROVIDED"}</BICFI></FinInstnId></CdtrAgt>
                            <RmtInf><Ustrd>{info}</Ustrd></RmtInf>
                          </CdtTrfTxInf>
                    """);
                progress?.Report(100.0 * ++i / count);
            }

            await _writer.WriteLineAsync("""
                    </PmtInf>
                  </CstmrCdtTrfInitn>
                </Document>
                """);
            await _writer.FlushAsync();
            progress?.Report(100.0);
        }
    }
}