using Elwig.Models.Entities;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Elwig.Helpers.Export {
    public class VCard : IExporter<Member> {

        public static string FileExtension => "vcf";

        private readonly StreamWriter _writer;

        public VCard(string filename) : this(filename, Utils.UTF8) { }

        public VCard(string filename, Encoding encoding) {
            _writer = new StreamWriter(filename, false, encoding);
        }

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

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

        public async Task ExportAsync(IEnumerable<Member> data, IProgress<double>? progress = null) {
            progress?.Report(0.0);
            int count = data.Count() + 1, i = 0;

            foreach (var row in data) {
                var billingAddr = row.BillingAddress != null ? $"ADR;TYPE=work;LANGUAGE=de;LABEL=\"{Escape(row.BillingAddress.FullName)}\\n{Escape(row.BillingAddress.Address)}\\n{row.BillingAddress.PostalDest.AtPlz?.Plz} {Escape(row.BillingAddress.PostalDest.AtPlz?.Ort.Name)}\\nÖsterreich\":;;{Escape(row.BillingAddress.Address)};{Escape(row.BillingAddress.PostalDest.AtPlz?.Ort.Name)};;{row.BillingAddress.PostalDest.AtPlz?.Plz};Österreich\r\n" : null;
                var tel = string.Join("", row.TelephoneNumbers
                    .Where(n => n.Type != "fax")
                    .Select(n => $"TEL;TYPE={(n.Type == "mobile" ? "cell" : "voice")}:{Escape(n.Number)}\r\n"));
                var email = string.Join("", row.EmailAddresses.Select(a => $"EMAIL:{Escape(a.Address)}\r\n"));
                await _writer.WriteLineAsync($"""
                    BEGIN:VCARD
                    VERSION:4.0
                    UID:mg{row.MgNr}@{App.Client.NameToken.ToLower()}.elwig.at
                    NOTE:MgNr. {row.MgNr}
                    FN:{Escape(row.AdministrativeName)}
                    N:{Escape(row.Name)};{Escape(row.GivenName)};{Escape(row.MiddleName)};{Escape(row.Prefix)};{Escape(row.Suffix)}
                    KIND:{(row.IsJuridicalPerson ? "org" : "individual")}
                    ADR{(billingAddr == null ? "" : ";TYPE=home")};LANGUAGE=de;LABEL="{Escape(row.Address)}\n{row.PostalDest.AtPlz?.Plz} {Escape(row.PostalDest.AtPlz?.Ort.Name)}\nÖsterreich":;;{Escape(row.Address)};{Escape(row.PostalDest.AtPlz?.Ort.Name)};;{row.PostalDest.AtPlz?.Plz};Österreich
                    {billingAddr}{tel}{email}REV:{row.ModifiedAt.ToUniversalTime():yyyyMMdd\THHmmss\Z}
                    END:VCARD
                    """);
                progress?.Report(100.0 * ++i / count);
            }

            await _writer.FlushAsync();
            progress?.Report(100.0);
        }

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

        private static string? Escape(string? text) {
            return text?.Replace("\\", "\\\\").Replace(",", "\\,").Replace(";", "\\;").Replace("\n", "\\n").Replace("\r", "");
        }
    }
}
