import {
    sleep, JSON2CSV, createZip, renameZipFile,
} from "./util.js";
import { headers } from "./header.js";

const DELAY = 2000;  // 2s

export class TaskGroup {
    constructor(tasks, options = {}) {
        this.tasks = tasks;
        this.task0 = tasks[0];
        this.unique = options.unique;
        this.len = this.unique ? 1 : this.tasks.length;
    }
    getFileName() {
        const pf = this.len > 1 ? this.len : null;
        return this.task0.getFileName(pf).replace(/\.\w+$/g, ".zip");
    }
    async send() {
        let fns = [];
        let blobs = (
            await Promise.all(
                this.tasks
                    .map(async (task, idx) => {
                        if (this.unique) {
                            task.options.retText = true;
                        }
                        const pf = this.len > 1 ? `${this.len}-${idx + 1}` : null;
                        const result = await task.send(true);
                        fns.push(task.getFileName(pf));
                        return result;
                    })))
            .filter(x => x !== false && x !== true);
        if (this.unique) {
            const reg = /\n|\r/g;  // 换行符
            blobs = [blobs.reduce((prev, cur) => {
                return (prev.match(reg)?.length || 0) > (cur.match(reg)?.length || 0) ? prev : cur;
            })];
            fns = [this.task0.getFileName()];
        }
        if (blobs.length > 0) {
            return createZip(blobs, fns);
        } else {
            return false;
        }
    }
}
export class Task {
    static partnerId = null;
    static uri = null;
    static desc = null;
    constructor(names, params, options) {
        this.names = names;
        this.params = params;
        this.options = options || {};
        this.uri = names.uri || Task.uri;
        this.partnerId = names.partnerId || Task.partnerId;
        this.desc = names.desc || Task.desc;
        if (!(this.uri && this.partnerId)) {
            throw new Error(`uri: ${this.uri}, partnerId: ${this.partnerId}`);
        }
        this._retryLimit = 6
        this._retryCount = 0
    }
    getFileName(sf) {
        const ext = this.options.ext || 'csv';
        let name = this.names.showName;
        name = this.options.noLowerCase ? name : name.toLowerCase();
        sf = sf === undefined || sf === null ? '' : ' ' + sf;
        return `${this.partnerId} #${name}# ${this.desc}${sf}.${ext}`;
    }
    async _retry(args) {
        if (++this._retryCount < this._retryLimit) {
            await sleep(DELAY * this._retryCount);
            const result = await this.send(...args);  // bind
            this._retryCount = 0;
            return result;
        } else {
            console.error(`重试失败: ${JSON.stringify(this)}`);
            this._retryCount = 0;
            return false;
        }
    }
    async send(next = false) {
        const url = new URL(`${this.uri}${this.names.apiName || ''}`);
        const method = this.options.method || 'GET';
        const callback = this.options.callback;
        const ext = this.options.ext || 'csv';
        next |= this.options.next;

        let body = this.options.body;
        body = (body && JSON.stringify(body)) || null;
        url.search = new URLSearchParams(this.params).toString();
        console.log(`${method} ${url}`);
        try {
            let response = await fetch(url, {
                body,
                method,
                headers: this.options.headers || headers,
                ...this.options.requestInit
            });
            console.log(response);
            if (response.status !== 200) {
                const text = await response.text();
                console.log(`重试请求, ${response.url}, ${text}`);
                return this._retry(arguments);
            }

            let blob;
            if (callback) {
                try {
                    blob = await callback.call(this, response);
                } catch (e) {
                    console.error(`重试回调, ${e.message}`);
                    return this._retry(arguments);
                }
            } else if (ext == 'json') {
                const json = await response.json();
                if (Object.keys(json).length === 0) {
                    return true;
                }
                const csv = JSON2CSV(json);
                blob = new Blob([csv], { type: "text/csv" });
                this.options.ext = "csv";
            } else {
                blob = await response.blob();
            }
            if (blob === undefined || blob === null) return false;
            if (next) return blob;
            const fn = this.getFileName();
            if (ext === 'zip') {
                const newFn = fn.replace(/\.\w+$/g, ".csv");
                return renameZipFile(blob, newFn);
            }
            return createZip([blob], [fn]);
        } catch (e) {
            if (e.message === 'Failed to fetch') {
                console.info(`重试 fetch`);
                return this._retry(arguments);
            }
            console.error(`send ${e.message} ${JSON.stringify(this)}`);
            return false;
        }
    }
}