import {
    sleep, getValue, fmt0, fmt2, fmt3,
    checkResponse, decodeState2, retry,
} from "./util.js";
import { Task, TaskGroup } from "./task.js";
import { getMouth, isLatestDate, cutDate } from "./timezone.js";
import { rrHeaders, headers } from "./header.js";
import { TABLE } from "./conf.js";

const DELAY = 2000;  // 2s

const inventoryHealthCallback = async function (response) {
    let data = await response.json();
    const url = data.downloadUrl;
    if (!url) {
        throw new Error(`downloadUrl 获取失败: ${JSON.stringify(data)}`);
    }
    console.log(`GET ${url}`);
    await sleep(DELAY);
    response = await fetch(url, { headers });
    console.log(response);
    await checkResponse(response);
    if (this.options.retText) return response.text();
    return response.blob();
}
const advertCallback = async function (response) {
    let { reportType = null, recommendationType = null, startDate = null, endDate = null } = this.options.body;
    reportType ||= recommendationType;
    const waitDone = async () => {
        try {
            await sleep(DELAY);
            response = await fetch(url, { headers });
            console.log(response);
            data = await response.json();
            const item = data.response.filter((item) => {
                return item.reportType === reportType
                    && isLatestDate(item.requestedOn)
                    && item.startDate === startDate
                    && item.endDate === endDate
            })[0];
            if (!item) {
                throw new Error(JSON.stringify(data));
            }
            url = item.download;
            console.log(`GET ${url}`);
            await sleep(DELAY);
            response = await fetch(url, { headers });
            console.log(response);
            await checkResponse(response);
            if (this.options.retText) return response.text();
            return response.blob();
        } catch (e) {
            console.log(`重试请求, ${e.message}`);
            if (++i < limit) return await waitDone();
        }
        throw new Error("重试失败");
    }

    let data = await response.json();
    const snapshotId = data.response && data.response.snapshotId;
    if (!snapshotId) {
        throw new Error(`snapshotId 获取失败: ${JSON.stringify(data)}`);
    }
    console.log(`snapshotId: ${snapshotId}`);
    let url = new URL(`${this.uri}${this.names.apiName}`);
    const advertiserId = this.options.body.advertiserId;
    url.search = new URLSearchParams({
        request: `/v1/snapshot/report?advertiserId=${advertiserId}&jobStatus=done`
    }).toString();
    console.log(`GET ${url}`);

    let limit = 30, i = 0;
    return waitDone();
}
const rrCallback = async function (response) {
    const headers = this.options.headers;
    const waitDone = async () => {
        let url = new URL(`${this.uri}${this.names.apiName}`);
        url.search = new URLSearchParams({
            reportType: "ORDER",
            reportVersion: "v1",
            page: "1",
            limit: "10"
        }).toString();
        console.log(`GET ${url}`);
        await sleep(DELAY * 30);  // 60s
        response = await fetch(url, { headers: headers });
        console.log(response);
        let data = await response.json();
        if (data.requests) {
            const request = data.requests.find((item) => item.requestId === requestId);
            if (request && request.requestStatus === "READY") {
                return;
            }
        }
        console.log(`重试请求, ${JSON.stringify(data)}`);
        if (++i < limit) return await waitDone();
    }

    let data = await response.json();
    const requestId = data.requestId;
    if (!requestId) {
        throw new Error(`requestId 获取失败: ${JSON.stringify(data)}`);
    }
    console.log(`requestId: ${requestId}`);

    let limit = 40, i = 0;
    await waitDone();

    let url = new URL(`${this.uri}${this.names.apiName2}`);
    url.search = new URLSearchParams({
        "reportType": "ORDER",
        "reportVersion": "v1",
        requestId
    }).toString();
    console.log(`GET ${url}`);
    await sleep(DELAY);
    response = await fetch(url, { headers: this.options.headers });
    console.log(response);
    data = await response.json();
    url = data.downloadURL;
    if (!url) {
        throw new Error(`downloadURL 获取失败: ${JSON.stringify(data)}`)
    }
    // 跨域
    const fn = this.getFileName();
    response = await chrome.runtime.sendMessage({
        type: "sopLink",
        data: { url, fn },
    });
    console.log(response);
    return null;
}
const gqlCallback = async function (response) {
    const uri = this.uri, method = "POST", { body, headers, fromDate, toDate } = this.options;
    async function getID(json) {
        const { campaignReports = null, pagination = null } = json.data.get_coop_campaigns;
        if (!campaignReports?.length) {
            return;
        }
        campaignReports.forEach((report) => {
            ids.add(report.id);
        });
        const { pageNo, totalPages } = pagination;
        if (pageNo < totalPages) {
            body.variables.campaignSummary.page.pageNumber += 1;
            response = await fetch(uri, { headers, method, body: JSON.stringify(body) });
            console.log(response);
            await checkResponse(response);
            json = await response.json();
            await getID(json);
        }
    }
    async function getData(campaignId, pageNumber) {
        const body = JSON.stringify({
            "query": `
    query get_coop_campaign($itemLevelSummary: ItemLevelSummaryReportRequest!) {
  get_coop_campaign(itemLevelSummary: $itemLevelSummary) {
    pagination {
      pageNo
      pageSize
      totalCount
      totalPages
    }
    itemLevelReports {
      id
      name
      imageUrl
      status
      offerPrice
      competitorPrice
      offerId
      sku
      olqScore
      productId
      demand
      googlePrice
      sameSeller14Day {
        gmv
        roas
      }
      issues
      traffic {
        clicks
        ctr
        cpc
        adspend
        impressions
      }
      url
    }
  }
}
    `,
            "variables": {
                itemLevelSummary: {
                    campaignId,
                    sort: {
                        attributionType: "same_seller",
                        sortBy: "adspend",
                        sortOrder: "DESC",
                    },
                    startDate: fromDate,
                    endDate: toDate,
                    page: {
                        pageNumber,
                        limit: 10,
                    },
                },
            },
        });
        response = await fetch(uri, { headers, method, body });
        console.log(response);
        await checkResponse(response);
        const json = await response.json();
        const { itemLevelReports = null, pagination = null } = json.data.get_coop_campaign;
        if (!itemLevelReports?.length) {
            return;
        }
        const item = itemLevelReports.map((itemLevelReport) => {
            return {
                ItemID: itemLevelReport.id,
                SKU: itemLevelReport.sku,
                Spend: itemLevelReport.traffic?.adspend || 0
            };
        });
        data.push(...item);
        const { pageNo, totalPages } = pagination;
        if (pageNo < totalPages) {
            await getData(campaignId, pageNo + 1);
        }
    }
    const data = [], ids = new Set(), json = await response.json();
    await getID(json);
    console.log(ids);
    for (const id of ids) {
        await getData(id, 0);
    }
    if (!data.length) {
        return null;
    }
    const newJson = { status: "OK", data }
    newJson.__route = "search_engine_marketing";
    if (this.params.requestType === "OPEN_CYCLE") {
        newJson["payCycleStatus"] = "open";
        this.names.showName += " open";
    }
    newJson["walmartid"] = this.partnerId;
    newJson["Starttime"] = fromDate;
    newJson["Endtime"] = toDate;
    return newJson;
}
const jsonCallback = async function (response) {
    const json = await response.json();
    const status = json.status;
    response = JSON.parse(
        JSON.stringify(json.payload.response)
            .replace(/\[\]|{}/g, '""')
    );
    const newJson = { status, ...response }
    newJson.__route = "transmitexportthispagedata";
    newJson["walmartid"] = this.partnerId;
    newJson["Starttime"] = this.params.fromDate;
    newJson["Endtime"] = this.params.toDate;
    // newJson[""] = this.params.settleDate;
    return newJson;
}
const getPeriods = async (options = {}) => {
    const url = "https://seller.walmart.com/aurora/v1/auroraPaymentsSettlementService/payment/settlementPeriods";
    console.log(`GET ${url}`);
    let response = await fetch(url, { headers });
    console.log(response);
    let data = await response.json();
    response = data.payload && data.payload.response;
    if (!response) {
        console.error(`response 获取失败: ${JSON.stringify(data)}`);
        throw new Error(response);
    }
    // response.shift();
    const { start = 0, end = 3, isBimester = false } = options;
    let periods;
    if (isBimester) {
        const prevMouth = getMouth(null, -1);
        const curMouth = fmt0(new Date()).slice(0, -3);
        const reg = new RegExp(`^${prevMouth}|^${curMouth}`);
        periods = response.filter((x) => reg.test(x.payPeriodFromDate) || reg.test(x.settleDate));
    } else {
        periods = response.slice(start, end);
    }
    console.log(`periods: ${JSON.stringify(periods)}`);
    return periods;
}
const getCutOffDate = async () => {
    const url = "https://seller.walmart.com/aurora/v1/wfs/seller-management-service/get-all-ccm-flags?version=v2"
    let response = await fetch(url, { headers });
    console.log(response);
    let data = await response.json();
    return data.featureFlags.dcaReturnsReport.featureInfo.cutOffDate;
}
const createAdvertTask = function (sign, bodyArgs, options = {}) {
    const getTaskOptions = (advertiserId) => {
        advertiserId ||= localStorage.getItem("advertiserId");
        return {
            method: 'POST',
            body: {
                format: "gzip",
                advertiserId,
                ...bodyArgs,
            },
            // noLowerCase: true,
            callback: advertCallback,
            isMmonthly: options.isMmonthly,
        }
    }

    const aids = decodeState2(options.initialState)?.advertisers.map((x) => x.id) || [];
    const names = {
        apiName: "campaigns",
        showName: `Advert ${sign}`,
        fileName: sign.replaceAll(' ', ''),
    }
    const params = {
        request: options.request || "/v1/snapshot/report"
    }
    if (aids.length > 1) {
        return new TaskGroup(
            aids.map((aid) => {
                return new Task(names, params, getTaskOptions(aid));
            }), { unique: true });
    } else {
        return new Task(names, params, getTaskOptions());
    }
}
const createOrderTask = function (sign, bodyArgs, options = {}) {
    const { fromDate, toDate } = bodyArgs;
    return new Task(
        {
            apiName: "reportRequests",
            apiName2: "downloadReport",
            showName: options.showName,
        },
        {
            reportType: "ORDER",
            reportVersion: "v1",
            isDSV: "false",
            bizRole: "MP",
        },
        {
            method: "POST",
            body: {
                rowFilters: [
                    {
                        type: "enumFilter",
                        values: ["All"],
                        columnName: "orderGroups",
                    },
                    {
                        type: "enumFilter",
                        values: [sign],
                        columnName: "fulfilmentTypes",
                    },
                    {
                        type: "rangeFilter",
                        columnName: "orderDate",
                        from: fromDate,
                        to: toDate,
                    },
                ],
                additionalInfo: {
                    reportSummary: `${sign} Fulfilled - ${fmt2(fromDate)} to ${fmt2(toDate)}`,
                },
                excludeColumns: ["Order Type", "Service PO#", "Service Status", "Total Service Cost", "Service Scheduled Date"],
            },
            headers: {
                ...rrHeaders(),
            },
            callback: rrCallback,
            ext: "xlsx",
        }
    );
};
export async function createTasks(uri, fromDate, toDate) {
    if (!uri.startsWith(location.origin)) {
        return [];
    }
    uri = uri || TABLE.WFS.uri;
    Task.partnerId = sessionStorage.getItem('partnerId');
    Task.uri = uri;  // 不适用于异步
    if (fromDate && toDate) {
        Task.desc = `${fromDate}_${toDate}`;  // 默认
    }
    switch (uri) {
        case TABLE.PAYMENT.uri:
            {
                const periods = (await retry(getPeriods, { isThrow: false }, [{ isBimester: true }])) || [];
                await sleep(DELAY);
                const tasks = [];
                Task.uri = uri;
                for (const period of periods) {
                    fromDate = period.payPeriodFromDate;
                    toDate = period.payPeriodToDate;
                    const { settleDate, payCycleStatus: requestType } = period;
                    const reportDate = fmt3(settleDate);
                    Task.desc = `${fromDate}_${toDate}`;
                    if (requestType !== "OPEN_CYCLE") {
                        tasks.push(
                            new Task(
                                {
                                    apiName: "report/reconreport/v1/reconFile",
                                    showName: "Payments new report",
                                },
                                {
                                    reportDate,
                                },
                                {
                                    ext: "zip",
                                }
                            ),
                            new Task(
                                {
                                    apiName: "report/reconreport/reconFile",
                                    showName: "Payments legacy report",
                                },
                                {
                                    reportDate,
                                },
                                {
                                    ext: "zip",
                                }
                            )
                        );
                    }
                    tasks.push(
                        new Task(
                            {
                                apiName: "auroraPaymentsSettlementService/payment/settlementDetails",
                                showName: "Export This Page",
                            },
                            {
                                settleDate,
                                fromDate,
                                toDate,
                                requestType,
                            },
                            {
                                ext: "json",
                                callback: jsonCallback,
                                next: true,
                            }
                        )
                    );
                }
                return tasks;
            }
        case TABLE.GQL.uri:
            {
                const body = {
                    query: `
    query get_coop_campaigns($campaignSummary: CampaignSummaryRequest!) {
  get_coop_campaigns(campaignSummary: $campaignSummary) {
    pagination {
      pageNo
      pageSize
      totalCount
      totalPages
    }
    campaignReports {
      id
      name
      startDate
      endDate
      status
      labels
      budget
      dailyBudget
      targetRoas
      sameSeller14Day {
        gmv
        roas
      }
      traffic {
        clicks
        adspend
        cpc
        impressions
        ctr
      }
      biddingStrategyType
      campaignRecommendations {
        type
        subType
        recommendedValue
        status
      }
      creationType
    }
  }
}
    `,
                    variables: {
                        campaignSummary: {
                            startDate: fromDate,
                            endDate: toDate,
                            name: "",
                            statuses: ["RUNNING", "COMPLETED", "STOPPED", "ERROR", "PAUSED"],
                            page: {
                                limit: 10,
                                pageNumber: 0,
                            },
                            sort: {
                                sortBy: "status",
                                sortOrder: "ASC",
                                attributionType: "same_seller",
                            },
                        },
                    },
                };
                return [
                    new Task(
                        {
                            apiName: "",
                            showName: "Search Engine Marketing",
                        },
                        {},
                        {
                            method: "POST",
                            ext: "json",
                            body,
                            fromDate,
                            toDate,
                            headers: rrHeaders(),
                            callback: gqlCallback,
                            next: true,
                        }
                    ),
                ];
            }
        case TABLE.ORDER.uri:
            return [
                new TaskGroup([
                    createOrderTask("WFS", { fromDate, toDate }, { showName: "Orders" }),
                    createOrderTask("Seller", { fromDate, toDate }, { showName: "Orders Seller" }),
                ])
            ];
        case TABLE.ADVERT.uri:
            {
                const initialState = await chrome.runtime.sendMessage({ type: "executeScript", data: "initialState" });
                const initialUrl = performance.getEntriesByType("navigation")[0]?.name || location.href;
                Task.partnerId = getValue("partner_id", initialUrl, "&");
                Task.uri = uri;
                return [
                    createAdvertTask(
                        "Keyword Performance",
                        {
                            startDate: fromDate,
                            endDate: toDate,
                            reportType: "keyword",
                            attributionWindow: "days3",
                            extraFields: ["noDate"],
                        },
                        { initialState, isMmonthly: true }
                    ),
                    createAdvertTask(
                        "Placement Performance",
                        {
                            startDate: fromDate,
                            endDate: toDate,
                            reportType: "placement",
                            attributionWindow: "days3",
                            extraFields: ["noDate"],
                        },
                        { initialState, isMmonthly: true }
                    ),
                    createAdvertTask(
                        "Item Keyword Performance",
                        {
                            startDate: fromDate,
                            endDate: toDate,
                            reportType: "itemKeyword",
                            attributionWindow: "days3",
                            extraFields: ["noDate"],
                        },
                        { initialState, isMmonthly: true }
                    ),
                    createAdvertTask(
                        "Item Performance",
                        {
                            startDate: fromDate,
                            endDate: toDate,
                            reportType: "adItem",
                            attributionWindow: "days3",
                            extraFields: ["noDate", "splitAttribution"],
                        },
                        { initialState }
                    ),
                    createAdvertTask(
                        "Keyword Recommendations",
                        {
                            recommendationType: "keywordRecommendations",
                        },
                        {
                            request: "/v1/snapshot/recommendations",
                            initialState,
                            isMmonthly: true
                        }
                    ),
                ];
            }
        default:
            {
                const cutOffDate = (await retry(getCutOffDate, { isThrow: false })) || "";
                const [se, cut] = cutDate([fromDate, toDate], cutOffDate);
                Task.uri = uri;
                return [
                    new Task(
                        {
                            apiName: "salesReport",
                            showName: "WFS Orders",
                        },
                        {
                            fromDate,
                            toDate,
                        },
                        { ext: "json", isMmonthly: true }
                    ),
                    new Task(
                        {
                            apiName: "salesReport",
                            showName: "WFS Multchannel_Fulfillment_Details",
                        },
                        {
                            fromDate,
                            toDate,
                            type: "MCS",
                        },
                        { ext: "json", isMmonthly: true }
                    ),

                    new TaskGroup(
                        [
                            new Task(
                                {
                                    apiName: "returnsReport",
                                    showName: "Customer returns",
                                },
                                {
                                    fromDate,
                                    toDate: cut ? cutOffDate : toDate,
                                },
                                { ext: "json" }
                            ),
                            new Task(
                                {
                                    apiName: "customerReturnsReportDca",
                                    showName: "New customer returns",
                                },
                                {
                                    fromDate: cut ? cutOffDate : fromDate,
                                    toDate,
                                },
                                { ext: "json" }
                            ),
                        ].slice(...se)
                    ),

                    new Task(
                        {
                            apiName: "inventoryReconciliation",
                            showName: "Inventory reconciliation",
                        },
                        {
                            fromDate,
                            toDate,
                        },
                        { isMmonthly: true }
                    ),
                    new Task(
                        {
                            apiName: "poAudit",
                            showName: "Inbound receipts",
                        },
                        {
                            fromDate,
                            toDate,
                            gtin: "",
                        },
                        { isMmonthly: true }
                    ),
                    new Task(
                        {
                            apiName: "feeDetailReport",
                            showName: "Settlement",
                        },
                        {
                            startDate: fromDate,
                            endDate: toDate,
                        }
                    ),
                    new Task(
                        {
                            apiName: "storageFeeReport",
                            showName: "Storage",
                        },
                        {
                            startDate: fromDate,
                            endDate: toDate,
                        }
                    ),
                    new Task(
                        {
                            apiName: "inboundTransportationReport",
                            showName: "Inbound transportation",
                        },
                        {
                            startDate: fromDate,
                            endDate: toDate,
                        },
                        { isMmonthly: true }
                    ),

                    new Task(
                        {
                            apiName: "inventoryHealthReport",
                            showName: "Inventory health",
                        },
                        {},
                        { callback: inventoryHealthCallback }
                    ),
                    new Task(
                        {
                            apiName: "inventoryHealthReport",
                            showName: "Inventory health mcs",
                        },
                        {
                            reportType: "multichannel",
                        },
                        { callback: inventoryHealthCallback, isMmonthly: true }
                    ),
                ];
            }
    }
}
