import dotenv from 'dotenv';
import https from 'https';
import axios from "axios";
import { HttpsProxyAgent } from "https-proxy-agent";
import Logs from "./logs.js";
import { getAccountInfo } from "./getAccount.js";

dotenv.config();

const axiosDefaultOptions = {
  baseURL: "",
  url: "",
  method: "GET",
  headers: {},
  params: {},
  data: {},
  timeout: 10000,
};

const BaseURL = {
  pinnacle: "https://api.pinnacle888.com",
  ps3838: "https://api.ps3838.com",
  pstery: "http://127.0.0.1:9055",
}

const betPostPaths = new Set([
  '/v4/bets/place',
  '/v4/bets/parlay',
  '/v4/bets/teaser',
  '/v4/bets/special',
]);

const cloneJsonData = (data) => {
  if (data === undefined || data === null) {
    return data;
  }
  return JSON.parse(JSON.stringify(data));
}

const toAccountCurrencyStake = (amount, accountInfo) => {
  const value = Number(amount);
  if (!Number.isFinite(value)) {
    return amount;
  }

  const currency = accountInfo?.currency?.toUpperCase() || 'USD';
  if (currency === 'USD') {
    return Math.round(value);
  }

  const rate = Number(accountInfo?.currencyInfo?.rate);
  if (!Number.isFinite(rate) || rate <= 0) {
    const error = new Error(`currency rate is not ready: ${currency}`);
    error.cause = 503;
    error.data = { currency };
    throw error;
  }

  return Math.round(value * rate);
}

const convertBetStakeToUsd = (data, accountInfo) => {
  if (!data || typeof data !== 'object') {
    return data;
  }

  const converted = cloneJsonData(data);
  const requests = Array.isArray(converted.bets) ? converted.bets : [converted];
  requests.forEach(request => {
    if (!request || typeof request !== 'object') {
      return;
    }

    if (request.stake !== undefined) {
      request.stake = toAccountCurrencyStake(request.stake, accountInfo);
    }

    if (request.riskAmount !== undefined) {
      request.riskAmount = toAccountCurrencyStake(request.riskAmount, accountInfo);
    }
  });

  return converted;
}

export const pinnacleRequest = async (options, channel) => {

  const accountInfo = getAccountInfo() ?? {};
  const { username, password, localAddress, platform } = accountInfo;
  const { data, params, url, ...optionsRest } = options;
  if (!url || !channel && (!username || !password)) {
    throw new Error("url、username、password、channel is required");
  }

  const requestData = !channel && optionsRest.method === 'POST' && betPostPaths.has(url)
    ? convertBetStakeToUsd(data, accountInfo)
    : data;

  Logs.outDev('pinnacle request', { url, channel, username, password, localAddress, platform });

  const authHeader = channel ? `Basic ${channel}` : `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
  const axiosConfig = { ...axiosDefaultOptions, ...optionsRest, data: requestData, params, url, baseURL: BaseURL[platform] ?? BaseURL.pinnacle };
  Object.assign(axiosConfig.headers, {
    "Authorization": authHeader,
    "Accept": "application/json",
  });
  const proxy = process.env.NODE_HTTP_PROXY;
  if (proxy) {
    axiosConfig.proxy = false;
    axiosConfig.httpsAgent = new HttpsProxyAgent(proxy);
    // Logs.outDev('pinnacle request using proxy', axiosConfig.httpsAgent);
  }
  else if (localAddress) {
    axiosConfig.httpsAgent = new https.Agent({ localAddress });
  }
  return axios(axiosConfig)
  .then(res => {
    // Logs.out('pinnacle request', url, axiosConfig, res.data);
    return res.data;
  })
  .catch(err => {
    let user_name = '';
    if (channel) {
      user_name = Buffer.from(channel, "base64").toString().split(':')[0];
    }
    else {
      user_name = username;
    }
    const source = { url, params, username: user_name };
    if (err?.response?.data) {
      const data = err.response.data;
      Object.assign(source, { data });
    }
    err.source = source;
    return Promise.reject(err);
  });
}

/**
 * Pinnacle API Get请求
 * @param {*} url
 * @param {*} params
 * @returns
 */
export const pinnacleGet = async (url, params, channel) => {
  return pinnacleRequest({
    url,
    params
  }, channel)
}

/**
 * Pinnacle API Post请求
 * @param {*} url
 * @param {*} data
 * @returns
 */
export const pinnaclePost = async (url, data, channel) => {
  return pinnacleRequest({
    url,
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data
  }, channel);
}


export const getPsteryRelations = async (mk=-1) => {
  const axiosConfig = {
    baseURL: BaseURL.pstery,
    url: '/api/pstery/get_games_relation',
    method: 'GET',
    params: {
      mk,
    },
    proxy: false,
  };

  return axios(axiosConfig).then(res => res.data);
}


export const updateBaseEvents = async (data) => {
  const axiosConfig = {
    baseURL: BaseURL.pstery,
    url: '/api/pstery/update_base_events',
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: JSON.stringify(data),
    proxy: false,
  };

  axios(axiosConfig).then(res => res.data)
  .then(() => {
    Logs.outDev('update base events success', data);
  })
  .catch(err => {
    Logs.err('failed to update base events:', err.response?.data ?? err.message);
  });
}


export const notifyException = async (message) => {
  const axiosConfig = {
    baseURL: BaseURL.pstery,
    url: '/api/pstery/notify_exception',
    method: 'POST',
    data: { message },
    proxy: false,
  };
  axios(axiosConfig).then(res => res.data)
  .then(() => {
    Logs.out('notify exception success');
  })
  .catch(err => {
    Logs.err('failed to notify exception:', err.message);
  });
}
