import * as path from "path";
import { AttachmentNativeBinding, MessageParserNativeBinding, SignExtendedInfo } from "../types";
import { NodeTrustedMailcore2NativeBinding } from '../types/NodeTrustedMailcore2NativeBinding';
import { Attachment } from './Attachment';
import { MessageHeader } from './MessageHeader';
import { KeyUsagePolicy } from "../enums/KuPolicyType";

// tslint:disable-next-line: no-var-requires
let bindings: NodeTrustedMailcore2NativeBinding;
try {
    bindings = require(path.join(__dirname, "../../lib/binding/trusted_mailcore2.node"));
} catch(e) {
    bindings = require(path.join(__dirname, "../../lib/binding/trusted_mailcore2_no_crypto.node"));
}

// tslint:disable-next-line
const { MessageParser: _MessageParser } = bindings;

/**
 * MessageParser Class
 *
 * @public
 */
class MessageParser extends bindings.MessageParser {
    protected handle: MessageParserNativeBinding

    /**
     * MessageParser class constructor
     *
     *
     * @param {string | Buffer} data Message data to parse
     * @param KeyUsagePolicy kuPolicy Key usage check policy
     * @memberof MessageParser
     */
    constructor(data?: string | Buffer, kuPolicy?: KeyUsagePolicy) {
        super();

        const handle = new _MessageParser(data, kuPolicy);
        this.handle = handle;
    }

    /**
     * Key usage policy getter
     *
     *
     * @type boolean
     * @memberof MessageParser
     */
    get doNotDecrypt(): boolean {
        return this.handle.doNotDecrypt;
    }

    /**
     * Key usage policy setter
     *
     *
     * @type boolean
     * @memberof MessageParser
     */
    set doNotDecrypt(decryptVal: boolean) {
        this.handle.doNotDecrypt = decryptVal;
    }

    /**
     * Key usage policy getter
     *
     *
     * @type KeyUsagePolicy
     * @memberof MessageParser
     */
    get keyUsagePolicy(): KeyUsagePolicy {
        return this.handle.keyUsagePolicy;
    }

    /**
     * Key usage policy setter
     *
     *
     * @type KeyUsagePolicy
     * @memberof MessageParser
     */
    set keyUsagePolicy(policyVal: KeyUsagePolicy) {
        this.handle.keyUsagePolicy = policyVal;
    }

    /**
     * Method to read data from file asynchronously
     *
     *
     * @param {string} fileName path to file with message to read
     * @memberof MessageParser
     */
    public ReadAsync(fileName: string): Promise<void> {
        return new Promise<void>((resolve, reject) => {
            this.handle.ReadAsync(fileName, ((error: string | Error | undefined | null) => {
                if (error) {
                    reject(error);
                }

                resolve();
            }));
        });
    }

    /**
     * Method to read data from file synchronously
     *
     *
     * @param {string} fileName path to file with message to read
     * @memberof MessageParser
     */
    public Read(fileName: string): void {
        this.handle.Read(fileName);
    }

    /**
     * Method to set folder for temporary files
     *
     *
     * @param {Buffer | string} data memory buffer to read data
     * @memberof MessageParser
     */
    public SetTempFolder(tmpFolderPath: string): void {
        this.handle.SetTempFolder(tmpFolderPath);
    }

    /**
     * Method to read data from memory asynchronously
     *
     *
     * @param {Buffer | string} data memory buffer to read data
     * @memberof MessageParser
     */
    public ImportAsync(data: Buffer | string): Promise<void> {
        return new Promise((resolve, reject) => {
            this.handle.ImportAsync(data, (error: string | Error | undefined | null) => {
                if (error) {
                    reject(error);
                }

                resolve();
            });
        });
    }

    /**
     * Method to read data from memory
     *
     *
     * @param {Buffer | string} data memory buffer to read data
     * @memberof MessageParser
     */
    public Import(data: Buffer | string): void {
        this.handle.Import(data);
    }

    /**
     * Message header getter
     *
     *
     * @type {MessageHeader}
     * @memberof MessageParser
     */
    get header(): MessageHeader | undefined {
        if (undefined === this.handle.header) {
            return undefined;
        }

        const value = new MessageHeader();
        value.handle = this.handle.header;

        return value;
    }

    // /**
    //  * Message header setter
    //  *
    //  *
    //  * @param {MessageHeader}  msgHeader
    //  * @memberof MessageParser
    //  */
    // set header(msgHeader: MessageHeader) {
    //     this.handle.header = msgHeader.handle;
    // }

    /**
     * Method to get rendered html from message
     *
     *
     * @type {string}
     * @memberof MessageParser
     */
    public HtmlRendering(): string {
        return this.handle.HtmlRendering();
    }

    /**
     * Method to get rendered html body from message
     *
     *
     * @type {string}
     * @memberof MessageParser
     */
    public HtmlBodyRendering(): string {
        return this.handle.HtmlBodyRendering();
    }

    /**
     * Method to get rendered plain text from message
     *
     *
     * @type {string}
     * @memberof MessageParser
     */
    public PlainTextRendering(): string {
        return this.handle.PlainTextRendering();
    }

    /**
     * Method to get rendered plain text body from message
     *
     *
     * @type {string}
     * @memberof MessageParser
     */
    public PlainTextBodyRendering(): string {
        return this.handle.PlainTextBodyRendering();
    }

    // /**
    //  * Main part getter
    //  *
    //  *
    //  * @type {MessagePart}
    //  * @memberof MessageParser
    //  */
    // get mainPart(): MessagePart {
    //     const value = new MessagePart();
    //     value.handle = this.handle.mainPart;
    //     return value;
    // }

    /**
     * Attachments getter
     *
     *
     * @type {Attachment[]}
     * @memberof MessageParser
     */
    get attachments(): Attachment[] {
        const attaches: AttachmentNativeBinding[] = this.handle.attachments;
        const result: Attachment[] = [];
        attaches.forEach((item: AttachmentNativeBinding) => {
            const value = new Attachment();
            value.handle = item;
            result.push(value);
        })
        return result;
    }

    /**
     * HTML inline attachments getter
     *
     *
     * @type {Attachment[]}
     * @memberof MessageParser
     */
    get htmlInlineAttachments(): Attachment[] {
        const attaches: AttachmentNativeBinding[] = this.handle.htmlInlineAttachments;
        const result: Attachment[] = [];
        attaches.forEach((item: AttachmentNativeBinding) => {
            const value = new Attachment();
            value.handle = item;
            result.push(value);
        })
        return result;
    }

    // /**
    //  * Required parts for rendering getter
    //  *
    //  *
    //  * @type {Part[]}
    //  * @memberof MessageParser
    //  */
    // get requiredPartsForRendering(): Part[] {
    //     const attaches: PartNativeBinding[] = this.handle.requiredPartsForRendering;
    //     const result: Part[] = [];
    //     attaches.forEach((item: PartNativeBinding) => {
    //         const value = new Part();
    //         value.handle = item;
    //         result.push(value);
    //     })
    //     return result;
    // }

    /**
     * Message is signed getter
     *
     *
     * @type {boolean}
     * @memberof MessageParser
     */
    get isSigned(): boolean {
        return this.handle.isSigned;
    }

    /**
     * Message is encrypted getter
     *
     *
     * @type {boolean}
     * @memberof MessageParser
     */
    get isEncrypted(): boolean {
        return this.handle.isEncrypted;
    }

    /**
     * Signed message verify result getter
     *
     *
     * @type {boolean}
     * @memberof MessageParser
     */
    get verifyResult(): boolean {
        return this.handle.verifyResult;
    }

    /**
     * Sertificate value getter (for signed messages)
     *
     *
     * @type {boolean}
     * @memberof MessageParser
     */
    get signerCertificate(): Buffer {
        return this.handle.signerCertificate;
    }

    /**
     * Signature extended information getter
     *
     *
     * @type {boolean}
     * @memberof MessageParser
     */
    get extendedSignInfo(): SignExtendedInfo | undefined {
        return this.handle.extendedSignInfo;
    }

    /**
     * Encrypted message decrypt result getter
     *
     *
     * @type {boolean}
     * @memberof MessageParser
     */
    get decryptResult(): boolean {
        return this.handle.decryptResult;
    }

    /**
     * Encrypted message description of decrypt result getter
     *
     *
     * @type {string}
     * @memberof MessageParser
     */
    get decryptMessage(): string {
        return this.handle.decryptMessage;
    }

    /**
     * Clears retained message data (and closes opened file)
     *
     *
     * @type {string}
     * @memberof MessageParser
     */
    public clear(): void {
        return this.handle.clear();
    }

     /**
     * Method to set license for portable version
     *
     *
     * @param {string} data license
     * @memberof MessageParser
     */
     public static SetLicense(lic: string): void {
        bindings.MessageParser.SetLicense(lic);
    }
}

export { MessageParser };
