//
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import Foundation

/// A pretty basic mailto: link builder
public struct MailtoLink {
    public var recipients: [String] = []
    public var ccRecipients: [String] = []
    public var bccRecipients: [String] = []

    public var subject: String
    public var body: String

    public init(to recipient: String, subject: String, body: String) {
        self.init(to: [recipient], subject: subject, body: body)
    }

    public init(to recipients: [String], subject: String, body: String) {
        self.recipients = recipients
        self.subject = subject
        self.body = body
    }

    public var url: URL? {
        let componentsBuilder = NSURLComponents()
        componentsBuilder.scheme = "mailto"
        componentsBuilder.percentEncodedPath = escapeList(recipients)

        let rawQueryItems = [
            ("cc", escapeList(ccRecipients)),
            ("bcc", escapeList(bccRecipients)),
            ("subject", escapeString(subject)),
            ("body", escapeString(body))
        ]
        let cleanedQueryItems = rawQueryItems
            .filter { !$0.1.isEmpty }
            .map { URLQueryItem(name: $0.0, value: $0.1) }

        componentsBuilder.percentEncodedQueryItems = cleanedQueryItems
        return componentsBuilder.url
    }

    // MARK: - Private

    private let allowableCharacters: CharacterSet = {
        var validChars = CharacterSet.urlPathAllowed
        // explicitly disallowed by RFC 6068
        validChars.remove(charactersIn: "%/?#[]&;=")
        // also drop commas and newlines for simplicity
        validChars.remove(charactersIn: ",\n")
        return validChars
    }()

    private func escapeString(_ string: String) -> String {
        return string.addingPercentEncoding(withAllowedCharacters: allowableCharacters) ?? ""
    }

    private func escapeList(_ list: [String]) -> String {
        return list
            .compactMap { escapeString($0) }
            .joined(separator: ",")
    }
}
