import { HttpClient } from 'aurelia-fetch-client';
import { computedFrom, inject } from "aurelia-framework";
import { Config } from  './../config';
export namespace RemoteFileStorage {

    export interface IServiceConfig {
        controller: string;
        secure?: boolean;
        canDownloadFiles?: boolean;
        ignoreUris?: Array<string>;
    }
    
    export interface IService {
        rotate(fileName: string, clockwise: boolean): Promise<string>;
        duplicate(fileName: string, newFolderName: string): Promise<string>;
        exists(fileName: string): Promise<boolean>;
        download(fileName: string): Promise<void>;
        fileUrl(fileName: string): Promise<string>;
        previewToken?(): Promise<string>;
        uploadBase64?(fileName: string, dataBase64: string): Promise<string>;
        readonly controller: string;
        readonly secure: boolean;
        readonly canDownloadFiles: boolean;
    }

    export abstract class Service implements IService {
        abstract rotate(fileName: string, clockwise: boolean): Promise<string>;
        abstract duplicate(fileName: string, newFolderName: string): Promise<string>;
        abstract exists(fileName: string): Promise<boolean>;
        abstract download(fileName: string): Promise<void>;
        abstract fileUrl(fileName: string): Promise<string>;
        abstract previewToken?(): Promise<string>;
        abstract uploadBase64?(fileName: string, dataBase64: string): Promise<string>;
        public controller: string;
        public secure: boolean;
        public canDownloadFiles: boolean;
    }

    export class ServiceValidator {
        public static implementsInterface(service: IService) {
            return service instanceof Service;
        }
    }

    @inject(HttpClient, Config)
    export class DWService extends Service {
        controller: string;
        canDownloadFiles: boolean;
        ignoreUris: Array<string>;

        constructor(public httpClient: HttpClient, public config: Config) {
            super();
            this.secure = this.config.globalConfig.remoteFileStorageServiceConfig.secure || false;
            this.controller = this.config.globalConfig.remoteServiceName + this.config.globalConfig.remoteFileStorageServiceConfig.controller;
            let canDownloadFiles = this.config.globalConfig.remoteFileStorageServiceConfig.canDownloadFiles;
            this.canDownloadFiles = canDownloadFiles == null ? !this.secure : canDownloadFiles;
            this.ignoreUris = this.config.globalConfig.remoteFileStorageServiceConfig.ignoreUris || [];
        }

        public async download(fileName: string): Promise<void> {
            if (!this.canDownloadFiles) return;
            let req = await this.httpClient.get(this.remoteFileReadUri + "?fileName=" + encodeURI(fileName));
            if (req != null) {
                let blob = await req.blob();
                let fileUrl = window.URL.createObjectURL(blob);
                let link = document.createElement('a');
                link.href = fileUrl;
                link.download = fileName != null ? fileName.substring(fileName.lastIndexOf('/') + 1) : fileUrl.substring(fileUrl.lastIndexOf('/') + 1);
                link.click();
                link.remove();
            }
            return;
        }

        async fileUrl(fileName: string): Promise<string> {
            if (fileName == null || fileName.trim().length == 0) return null;
            if ((!this.secure && fileName.startsWith("http")) || this.ignoreUris.some(uri => fileName.startsWith(uri))) return fileName;
            
            if (this.secure) {
                return this.remoteFilePreviewUri + "/" + (await this.previewToken()) + "?fileName=" + encodeURI(fileName);
            } else {
                return this.remoteFileReadUri + "?fileName=" + encodeURI(fileName);
            }
        }

        async previewToken(): Promise<string> {
            let req = await this.httpClient.get(this.remoteFileGetTokenUri);
            if (req.ok) {
                return (await req.text());
            }
        }

        async rotate(fileName: string, clockwise = true): Promise<string> {
            if (fileName == null || fileName.trim().length == 0) return null;
            var req = await this.httpClient.post(this.remoteFileRotateUri, JSON.stringify({
                "uri": fileName,
                "clockwise": clockwise
            }));
            if (req.ok) {
                return (await req.text());
            }
        }

        async duplicate(fileName: string, newFolderName: string): Promise<string> {
            if (fileName == null || fileName.trim().length == 0) return null;
            var req = await this.httpClient.post(this.remoteFileDuplicateUri, JSON.stringify({
                "uri": fileName,
                "folderName": newFolderName
            }));
            if (req.ok) {
                return (await req.text());
            }
        }

        async exists(fileName: string): Promise<boolean> {
            if (fileName == null || fileName.trim().length == 0) return false;
            let req = await this.httpClient.get(this.remoteFileExistsUri + '?fileName=' + fileName);
            if (req.ok) {
                return (await req.json()) as boolean;
            }
        }

        async uploadBase64(fileName: string, dataBase64: string): Promise<string> {
            if (fileName == null || fileName.trim().length == 0 || dataBase64 == null || dataBase64.trim().length == 0) return null;
            let req = await this.httpClient.post(this.remoteFileUploadBase64 + '?fileName=' + fileName, JSON.stringify(dataBase64));
            if (req.ok) {
                return (await req.json()).Url;
            }
        }

        @computedFrom('controller')
        public get remoteFileControllerUri() {
            return this.getRemoteActionUriByName('upload');
        }
        
        @computedFrom('controller')
        public get remoteFileExistsUri() {
            return this.getRemoteActionUriByName('exists');
        }

        @computedFrom('controller')
        public get remoteFileRotateUri() {
            return this.getRemoteActionUriByName('rotate');
        }

        @computedFrom('controller')
        public get remoteFileDuplicateUri() {
            return this.getRemoteActionUriByName('duplicate');
        }

        @computedFrom('controller')
        public get remoteFileReadUri() {
            return this.getRemoteActionUriByName('read');
        }

        @computedFrom('controller')
        public get remoteFileGetTokenUri() {
            return this.getRemoteActionUriByName('token');
        }

        @computedFrom('controller')
        public get remoteFilePreviewUri() {
            return this.getRemoteActionUriByName('preview');
        }
        
        @computedFrom('controller')
        public get remoteFileUploadBase64() {
            return this.getRemoteActionUriByName('uploadbase64');
        }

        protected getRemoteActionUriByName(name: string): string {
            if (this.controller == null || this.controller.length == 0) return 'You must configure a remote file service controller uri';
            return `${this.controller}${name}`;
        }
    }
}