/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { request } from "@altangent/lib-http";
import qs from "querystring";
import crypto from "crypto";
import { Results } from "./Results";

export class CoinbasePrimeClient {
    constructor(
        readonly key: string,
        readonly passphrase: string,
        readonly signingKey: string,
        readonly urlBase = "https://api.prime.coinbase.com",
    ) {}

    public async listPortfolios(): Promise<Results.PortfolioList> {
        return this.request("/v1/portfolios");
    }

    public async listPortfolioBalances(portfolio_id: string): Promise<Results.ListBalances> {
        return this.request(`/v1/portfolios/${portfolio_id}/balances`);
    }

    public async listPortfolioTransactions(
        portfolio_id: string,
        params?: Partial<{
            symbols: string;
            types: string[];
            start_time: string;
            end_time: string;
            cursor: string;
            limit: number;
            sort_direction: string;
        }>,
    ): Promise<Results.ListTransactions> {
        return this.request(`/v1/portfolios/${portfolio_id}/transactions`, params);
    }

    public async listPortfolioWallets(portfolio_id: string): Promise<Results.ListWallets> {
        return this.request(`/v1/portfolios/${portfolio_id}/wallets`);
    }

    public async listPortfolioOrders(
        portfolio_id: string,
        params?: Partial<{
            product_ids: string[];
            order_type: string;
            cursor: string;
            limit: string;
            sort_direction: string;
            start_date: string;
            order_side: string;
            end_date: string;
        }>,
    ): Promise<Results.ListOrders> {
        return this.request(`/v1/portfolios/${portfolio_id}/orders`, params);
    }

    /**
     * Refer to https://docs.cdp.coinbase.com/prime/reference/primerestapi_getportfoliofills
     * @param portfolio_id
     * @param params
     */
    public async listPortfolioFills(
        portfolio_id: string,
        params?: Partial<{
            cursor: string;
            limit: number;
            start_date: string;
            end_date: string;
            sort_direction: "ASC" | "DESC";
        }>,
    ): Promise<Results.PortfolioFills> {
        return this.request(`/v1/portfolios/${portfolio_id}/fills`, params);
    }

    public request<T>(path: string, query?: any): Promise<T> {
        const key = this.key;
        const passphrase = this.passphrase;
        const signingKey = this.signingKey;

        const pathQuery = query ? path + "?" + qs.encode(query) : path;

        const timestamp = Math.floor(new Date().getTime() / 1000);
        const method = "GET";
        const body = "";
        const sig = this._sign(this._createSigData(timestamp, method, path, body), signingKey);

        const headers = {
            "X-CB-ACCESS-KEY": key,
            "X-CB-ACCESS-PASSPHRASE": passphrase,
            "X-CB-ACCESS-SIGNATURE": sig.toString("base64"),
            "X-CB-ACCESS-TIMESTAMP": timestamp,
        };

        const url = this.urlBase + pathQuery;

        // eslint-disable-next-line @typescript-eslint/no-unsafe-call
        return request({ url, method, headers }) as Promise<T>;
    }

    protected _cleanOptions(options: any): any {
        const result = {};
        for (const key in options) {
            if (options[key] !== undefined) {
                result[key] = options[key];
            }
        }
        return result;
    }

    protected _createSigData(
        timestamp: number,
        method: string,
        path: string,
        body: string,
    ): string {
        return `${timestamp}${method.toUpperCase()}${path}${body}`;
    }

    protected _sign(data: string, key: string): Buffer {
        const hmac = crypto.createHmac("sha256", key);
        hmac.update(data, "utf-8");
        return hmac.digest();
    }
}
