import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Schema } from "./jsonschemas.service";
import {catchError} from "rxjs/operators";
import {from} from "rxjs";
import {SortDirection} from "./list/sortable.directive";


@Injectable()
export class ApiService {
    constructor(protected http: HttpClient) {}

    protected api_root: string = '/api/v1'

    public getSchema() {
        return this.http.get<Schema>(`${this.api_root}/openapi.json`);
    }
}

export class SortBy {
    column: string;
    direction: SortDirection;

    constructor(column: string, direction: SortDirection = 'asc') {
        this.column = column;
        this.direction = direction;
    }

    toString() {
        return `${this.direction}(${this.column})`;
    }
}

export class Filters {
    column: string;
    operator: string;
    value: string;

    constructor(column: string, operator: string, value: string) {
        this.column = column;
        this.operator = operator;
        this.value = value;
    }

    toString() {
        if (this.operator == "eq") {

        }
        return `${this.column} ${this.operator} ${this.value}`;
    }
}

export class Parameters {
    page: number;
    size: number;
    sortBy: SortBy[];
    filters: Filters[];

    constructor(page: number, size: number, sortBy: SortBy[], filters: Filters[]) {
        this.page = page;
        this.size = size;
        this.sortBy = sortBy;
        this.filters = filters;
    }

    toString() {
        let s = `size=${this.size}`;
        s += `&page=${this.page}`;
        if (this.sortBy.length > 0 ) {
            s += `&sort_by=${this.sortBy.join(',')}`;
        }
        if (this.filters.length > 0 ) {
            s += `&query=${encodeURIComponent(this.filters.join(' AND '))}`;
        }
        return s;
    }
}

@Injectable()
export class CrudService extends ApiService {

    public loading: boolean = false;

    public getList(resource: string, page: number, size: number, sortBy: SortBy[] = [], filters: Filters[] = []) {

        let params = new Parameters(page, size, sortBy, filters);

        return this.http.get<{ items: [{}] }>(
            `${this.api_root}/${resource.toLowerCase()}/?${params}`
        );
    }

    public get(resource: string, id: string) {
        return this.http.get<any>(
            `${this.api_root}/${resource.toLowerCase()}/${id}`
        );
    }

    public update(resource: string, model: any) {
        return this.http.put<{ menu: [{}] }>(
            `${this.api_root}/${resource.toLowerCase()}/${model._id}`,
            model
        );
    }

    public create(resource: string, model: any) {
        return this.http.post<{ menu: [{}] }>(
            `${this.api_root}/${resource.toLowerCase()}/`,
            model
        );
    }

    public delete(resource: string, model: any) {
        return this.http.delete<{ menu: [{}] }>(
            `${this.api_root}/${resource.toLowerCase()}/${model._id}`
        );
    }
}

@Injectable()
export class ImageUploaderCrudService extends CrudService {
    public upload(resource: string, signature_id: string, image: string) {
        const formData: FormData = new FormData();
        formData.append("signature_file", dataURIToBlob(image), signature_id + ".png");

        return this.http.post<{ menu: [{}] }>(
            `${this.api_root}/${resource.toLowerCase()}/${signature_id}`,
            formData
        );
    }
}

function dataURIToBlob(dataURI: string) {
    const splitDataURI = dataURI.split(',')
    const byteString = splitDataURI[0].indexOf('base64') >= 0 ? atob(splitDataURI[1]) : decodeURI(splitDataURI[1])
    const mimeString = splitDataURI[0].split(':')[1].split(';')[0]

    const ia = new Uint8Array(byteString.length)
    for (let i = 0; i < byteString.length; i++)
        ia[i] = byteString.charCodeAt(i)

    return new Blob([ia], { type: mimeString })
}