import Packet from "../packet";
import Stream from "../stream";

export enum AttachmentType {
    IMAGE = 0,
    MESSAGES = 1,
    FILE = 2,
    AVATAR = 3,
    CALL = 4
}

/**
 * Информация о транспортировке вложения, нужна для загрузки и скачивания вложений с транспортного сервера
 */
export interface AttachmentTransport {
    transport_tag: string;
    transport_server: string;
}


export interface Attachment {
    id: string;
    blob: string; 
    type: AttachmentType;
    preview: string;
    transport: AttachmentTransport;
} 

export class PacketMessage extends Packet {

    private fromPublicKey: string = "";
    private toPublicKey: string = "";
    private content: string = "";
    private chachaKey: string = "";
    private timestamp: number = 0;
    private privateKey: string = "";
    private messageId: string = "";
    /**
     * Закодированный с помощью AES ключ chacha, нужен
     * для последующей синхронизации своих же сообщений
     */
    private aesChachaKey: string = "";
    
    private attachments: Attachment[] = [];

    public getPacketId(): number {
        return 0x06;
    }

    public _receive(stream: Stream): void {
        this.fromPublicKey = stream.readString();
        this.toPublicKey = stream.readString();
        this.content = stream.readString();
        this.chachaKey = stream.readString();
        this.timestamp = Number(stream.readInt64());
        this.privateKey = stream.readString();
        this.messageId = stream.readString();
        let attachmentsCount = stream.readInt8();
        for(let i = 0; i < attachmentsCount; i++){
            let id = stream.readString();
            let preview = stream.readString();
            let blob = stream.readString();
            let type = stream.readInt8() as AttachmentType;
            const transport : AttachmentTransport = {
                transport_tag: stream.readString(),
                transport_server: stream.readString()
            }
            this.attachments.push({id, preview, type, blob, transport});
        }
        this.aesChachaKey = stream.readString();
    }
    
    public async _send(): Promise<Stream> {
        const stream = new Stream();
        stream.writeInt16(this.getPacketId());
        stream.writeString(this.fromPublicKey);
        stream.writeString(this.toPublicKey);
        stream.writeString(this.content);
        stream.writeString(this.chachaKey);
        stream.writeInt64(BigInt(this.timestamp));
        stream.writeString(this.privateKey);
        stream.writeString(this.messageId);
        stream.writeInt8(this.attachments.length);
        for(let i = 0; i < this.attachments.length; i++){
            stream.writeString(this.attachments[i].id);
            stream.writeString(this.attachments[i].preview);
            stream.writeString(this.attachments[i].blob);
            stream.writeInt8(this.attachments[i].type);
            stream.writeString(this.attachments[i].transport.transport_tag);
            stream.writeString(this.attachments[i].transport.transport_server);
        }
        stream.writeString(this.aesChachaKey);
        return stream;
    }

    public setAttachments(attachments: Attachment[]): void {
        this.attachments = attachments;
    }

    public getAttachments(): Attachment[] {
        return this.attachments;
    }

    public setMessageId(messageId: string): void {
        this.messageId = messageId;
    }

    public getMessageId(): string {
        return this.messageId;
    }

    public setTimestamp(timestamp: number): void {
        this.timestamp = timestamp;
    }

    public getTimestamp() : number {
        return this.timestamp;
    }

    public getFromPublicKey(): string {
        return this.fromPublicKey;
    }

    public getToPublicKey(): string {
        return this.toPublicKey;
    }

    public getContent(): string {
        return this.content;
    }

    public getChachaKey(): string {
        return this.chachaKey;
    }

    public setFromPublicKey(fromPublicKey: string): void {
        this.fromPublicKey = fromPublicKey;
    }

    public setToPublicKey(toPublicKey: string): void {
        this.toPublicKey = toPublicKey;
    }

    public setContent(content: string): void {
        this.content = content;
    }

    public setChachaKey(chachaKey: string): void {
        this.chachaKey = chachaKey;
    }
    
    public setPrivateKey(privateKey: string): void {
        this.privateKey = privateKey;
    }

    public getPrivateKey(): string {
        return this.privateKey;
    }

    public getAesChachaKey() : string {
        return this.aesChachaKey;
    }

    public setAesChachaKey(aesChachaKey: string) {
        this.aesChachaKey = aesChachaKey;
    }
}