# -*- coding: utf-8 -*-

import time
import json
import hashlib
import warnings
import hmac
from urllib.request import Request, urlopen
from urllib.error import HTTPError
from urllib.parse import urlencode
from typing import Union, List
from kuna import __version__


class APIError(Exception):
    def __init__(self, result):
        if isinstance(result, HTTPError):
            result = json.load(result)
        if isinstance(result, dict) and "messages" in result:
            message = result.get("messages")
        elif isinstance(result, str):
            message = result
        else:
            message = repr(result)
        Exception.__init__(self, message)


class KunaAPI:
    """
    Documentation sources
    - https://docs.kuna.io/docs
    - https://github.com/kunadevelopers/api-docs
    """

    API_VERSION = "3"
    DEFAULT_HEADERS = {
        "accept": "application/json",
        "content-type": "application/json",
        "user-agent": f"python-kuna/{__version__}",
    }
    KEYS_NEED_MESSAGE = """
        API initialized without public or private key. Only Public API is available.
        Get keys from "https://kuna.io/settings/api_tokens".
        """

    def __init__(
        self,
        public_key: str = None,
        private_key: str = None,
        disable_warnings: bool = False,
    ):
        self.public_key = public_key
        self.private_key = private_key
        self.endpoint = "https://api.kuna.io"
        self.prefix = "/v3"

        self._check_keys(error=False)
        if disable_warnings:
            warnings.filterwarnings("ignore")

    def _check_keys(self, error: bool = True):
        if (self.public_key is None) or (self.private_key is None):
            if error:
                raise APIError(self.KEYS_NEED_MESSAGE)
            else:
                warnings.warn(self.KEYS_NEED_MESSAGE)

    def _generate_sign(self, uri: str, body: str, nonce: str) -> str:
        """
        Signature is generated by an algorithm: https://docs.kuna.io/docs/api-data-schema-and-serialization
        HEX(HMAC-SHA384(URI + timestamp + JSON(params), secret_key))
        :return:
        """
        payload = "{}{}{}".format(uri, nonce, body)
        payload_bin = payload.encode("ascii")
        private_key_bin = self.private_key.encode("ascii")
        sign = hmac.new(private_key_bin, payload_bin, hashlib.sha384)
        return sign.hexdigest()

    def _request(
        self, path: str, args: dict = {}, body: dict = {}, is_user_method=False
    ) -> Union[dict, list, APIError]:
        """
        Fetches the given path in the Kuna API.
        :param path: Api path
        :param args: args of GET-request
        :param body: body of request
        :param is_user_method:
        :return: Serialized server response or error
        """
        # If GET params available then add it to path
        if args:
            path += "?" + urlencode(args)
        headers = self.DEFAULT_HEADERS.copy()
        body = json.dumps(body)

        if is_user_method:
            self._check_keys(error=True)
            nonce = str(int(time.time() * 1000))
            headers["kun-nonce"] = nonce
            headers["kun-apikey"] = self.public_key
            headers["kun-signature"] = self._generate_sign(
                self.prefix + path, body, nonce
            )

        method = "POST" if is_user_method else "GET"
        url = self.endpoint + self.prefix + path
        req = Request(url, body.encode(), headers, method=method)
        try:
            with urlopen(req) as resp:
                json_resp = json.load(resp)
        except HTTPError as err:
            raise APIError(err)
        else:
            return json_resp

    # Old methods
    def get_server_time(self):
        warnings.warn('Better use: "api.timestamp()"', DeprecationWarning)
        self.timestamp()

    def get_recent_market_data(self, market):
        warnings.warn('Better use: "api.tickers(market)"', DeprecationWarning)
        self.tickers(market)

    def get_order_book(self, market):
        warnings.warn('Better use: "api.book(market)"', DeprecationWarning)
        self.book(market)

    def get_trades_history(self, market):
        warnings.warn('Better use: "api.trades_hist(market)"', DeprecationWarning)
        self.trades_hist(market)

    def get_user_account_info(self):
        warnings.warn('Better use: "api.auth_me()"', DeprecationWarning)
        self.auth_me()

    def get_orders(self, market):
        warnings.warn('Better use: "api.auth_r_orders(market)"', DeprecationWarning)
        self.auth_r_orders(market)

    def put_order(self, side, amount, symbol, price):
        warnings.warn('Better use: "api.auth_w_order_submit()"', DeprecationWarning)
        if side.lower() == "buy":
            amount = abs(amount)
        else:
            amount = -1 * abs(amount)
        self.auth_w_order_submit(symbol, "limit", amount, price)

    def cancel_order(self, order_id):
        warnings.warn('Better use: "api.order_cancel(order_id)"', DeprecationWarning)
        self.order_cancel(order_id)

    def get_trade_history(self, market):
        warnings.warn(
            'Better use: "api.auth_r_orders_hist(market)"', DeprecationWarning
        )
        self.auth_r_orders_hist(market)

    # PUBLIC API
    def timestamp(self):
        """
        # Kuna server time.
        https://docs.kuna.io/docs/time-on-server
        :return: https://docs.kuna.io/reference#getv3timestamp
        """
        return self._request("/timestamp")

    def landing_page_statistic(self):
        """
        Info about Week and Day trades sum and number of traders
        :return: https://docs.kuna.io/reference#getv3landingpagestatistic
        """
        return self._request("/landing_page_statistic")

    def currencies(self):
        """
        List of available currencies. https://docs.kuna.io/docs/available-currencies-list
        :return: https://docs.kuna.io/reference#getv3currencies
        """
        return self._request("/currencies")

    def exchange_rates(self, currency: str = None):
        """
        Exchange rates for all currencies or specified one
        :param currency: like 'eth' or 'uah'
        :return: https://docs.kuna.io/reference#exchange-rates
        """
        if currency:
            path = f"/exchange-rates/{currency}"
        else:
            path = "/exchange-rates"
        return self._request(path)

    def markets(self):
        """
        # List of available markets https://docs.kuna.io/docs/markets
        :return: https://docs.kuna.io/reference#getv3markets
        """
        return self._request("/markets")

    def tickers(self, symbols: Union[str, list] = None):
        """
        Last ticker for certain or all markets.
        https://docs.kuna.io/docs/%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BD%D0%B8%D0%B5-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5-%D0%BF%D0%BE-%D1%80%D1%8B%D0%BD%D0%BA%D1%83-%D1%82%D0%B8%D0%BA%D0%B5%D1%80%D1%8B
        :param symbols: 'btcuah' or ['btcuah','kunbtc','ethuah'], by default ALL
        :return: https://docs.kuna.io/reference#getv3tickers
        """
        if isinstance(symbols, str):
            args = {"symbols": symbols}
        elif isinstance(symbols, list):
            args = {"symbols": ",".join(symbols)}
        else:
            args = {"symbols": "ALL"}
        return self._request("/tickers", args=args)

    def book(self, market):
        """
        Actual Orderbook state for certain market.
        https://docs.kuna.io/docs/%D0%BE%D1%80%D0%B4%D0%B5%D1%80%D0%B1%D1%83%D0%BA
        :param market: 'btcuah'
        :return: https://docs.kuna.io/reference#getv3bookmarket
        """
        return self._request(f"/book/{market}")

    def trades_hist(self, market: str):
        """
        Gets history of trades.
        https://docs.kuna.io/docs/transaction-history
        :return: https://docs.kuna.io/reference#getv3tradesmarkethist
        """
        return self._request(f"/trades/{market}/hist")

    def price_changes(self, *args, **kwargs):
        """
        Not implemented.
        https://docs.kuna.io/docs/%D0%B3%D1%80%D0%B0%D1%84%D0%B8%D0%BA-%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F-%D1%86%D0%B5%D0%BD%D1%8B  # noqa: 501
        :return:
        """
        raise NotImplementedError

    def fees(self):
        """
        Withdraw and deposit methods. Withdrawal fees. https://docs.kuna.io/docs/deposits-withdrowals-fees
        :return: https://docs.kuna.io/reference#getv3fees
        """
        return self._request("/fees")

    # PRIVATE API
    def http_test(self):
        """
        Test HTTP connection to private API
        :return: https://docs.kuna.io/reference#postv3httptest
        """
        return self._request("/http_test", is_user_method=True)

    def auth_me(self):
        """
        Information about the User-account
        https://docs.kuna.io/docs/%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5-%D0%B0%D0%BA%D0%BA%D0%B0%D1%83%D0%BD%D1%82%D0%B0  # noqa: E501
        :return:
        """
        return self._request("/auth/me", is_user_method=True)

    def auth_r_wallets(self):
        """
        Account balance in all wallets
        :return: https://docs.kuna.io/docs/account-balance
        """
        return self._request("/auth/r/wallets", is_user_method=True)

    def auth_history_trades(
        self, market: str, date_from: int = None, date_to: int = None
    ):
        """
        Send history of trade in csv-file to user EMAIL.
        https://docs.kuna.io/docs/%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B8%D1%81%D1%82%D0%BE%D1%80%D0%B8%D0%B8-%D1%81%D0%B4%D0%B5%D0%BB%D0%BE%D0%BA-%D0%BF%D0%BE-%D0%BF%D0%BE%D1%87%D1%82%D0%B5  # noqa: E501
        :param market: 'ethuah'
        :param date_from: UNIX timestamp. Default: year ago (now - 60*60*24*365)
        :param date_to: UNIX timestamp. Default: now
        :return:
        """
        body = {"market": market, "date_from": date_from, "date_to": date_to}
        return self._request("/auth/history/trades", body=body, is_user_method=True)

    # TRADE API
    def auth_r_orders(self, market: str = None):
        """
        List of active orders
        https://docs.kuna.io/docs/%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA-%D0%B0%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D1%85-%D0%BE%D1%80%D0%B4%D0%B5%D1%80%D0%BE%D0%B2
        :param market: Optional, by default returns all markets
        :return:
        """
        if market:
            path = f"/auth/r/orders/{market}"
        else:
            path = "/auth/r/orders"
        return self._request(path, is_user_method=True)

    def auth_r_orders_hist(self, market: str = None):
        """
        List of executed orders
        https://docs.kuna.io/docs/%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D0%BD%D0%B5%D0%BD%D0%BD%D1%8B%D1%85-%D0%BE%D1%80%D0%B4%D0%B5%D1%80%D0%BE%D0%B2
        :param market:
        :return:
        """
        if market:
            path = f"/auth/r/orders/{market}/hist"
        else:
            path = "/auth/r/orders/hist"
        return self._request(path, is_user_method=True)

    def auth_r_order_trades(self, market: str, order_id: int):
        """
        List of dealings for certain order
        https://docs.kuna.io/docs/%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA-%D0%B0%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D1%85-%D0%BE%D1%80%D0%B4%D0%B5%D1%80%D0%BE%D0%B2
        :param market: like 'btcuah'
        :param order_id: like 10000000
        :return:
        """
        return self._request(
            f"/auth/r/order/{market}:{order_id}/trades", is_user_method=True
        )

    def auth_w_order_submit(
        self,
        symbol: str,
        type: str,
        amount: float,
        price: float = None,
        stop_price: float = None,
    ):
        """
        Creates order
        https://docs.kuna.io/docs/%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D1%82%D1%8C-%D0%BE%D1%80%D0%B4%D0%B5%D1%80-1
        :param symbol: like 'ethuah'
        :param type: may be 'limit', 'market', 'market_by_quote', 'limit_stop_loss'
        :param amount: if BUY ETH - positive number, if SELL ETH - negative number
        :param price: price for 1 ETH in UAH. Necessary only when type='limit'
        :param stop_price: price when activates 'limit_stop_loss' type order. If None then price
        :return:
        """
        available_types = ("limit", "market", "market_by_quote", "limit_stop_loss")
        if type.lower() not in available_types:
            raise APIError(f'"{type}" is not one of available types {available_types}')

        body = {
            "symbol": symbol,
            "type": type,
            "amount": amount,
            "price": price,
            "stop_price": stop_price,
        }

        return self._request("/auth/w/order/submit", body=body, is_user_method=True)

    def order_cancel(self, order_id: int):
        """
        Cancel one order
        https://docs.kuna.io/docs/%D0%BE%D1%82%D0%BC%D0%B5%D0%BD%D0%B8%D1%82%D1%8C-%D0%BE%D1%80%D0%B4%D0%B5%D1%80
        :param order_id:
        :return: https://docs.kuna.io/reference#postv3ordercancel
        """
        body = {"order_id": order_id}
        return self._request("/order/cancel", body=body, is_user_method=True)

    def order_cancel_multi(self, order_ids: List[int]):
        """
        Cancel many orders
        https://docs.kuna.io/docs/%D0%BE%D1%82%D0%BC%D0%B5%D0%BD%D0%B8%D1%82%D1%8C-%D0%BE%D1%80%D0%B4%D0%B5%D1%80
        :param order_ids:
        :return: https://docs.kuna.io/reference#postv3ordercancelmulti
        """
        body = {"order_ids": order_ids}
        return self._request("/order/cancel/multi", body=body, is_user_method=True)

    # MERCHANT API
    def deposit_channels(self, currency: str):
        """
        List of allowed deposit channels
        :param currency:  like 'btc'
        :return: https://docs.kuna.io/reference#postv3depositchannels
        """
        body = {"currency": currency}
        return self._request("/deposit_channels", body=body, is_user_method=True)

    def withdraw_channels(self, currency: str):
        """
        List of allowed withdraw channels
        :param currency: like 'eth'
        :return: https://docs.kuna.io/reference#postv3withdrawchannels
        """
        body = {"currency": currency}
        return self._request("/withdraw_channels", body=body, is_user_method=True)

    def auth_payment_requests_address(
        self, currency: str, blockchain: str = None, callback_url: str = None
    ):
        """
        Generates new address for crypto deposit or error if address exists
        https://docs.kuna.io/docs/generate-new-address-for-deposit
        :param currency: like 'usdt'
        :param blockchain: like 'eth', 'trx'
        :param callback_url: to this URL will be send POST-request after successful deposit
        :return:
        """
        body = {
            "currency": currency,
            "blockchain": blockchain,
            "callback_url": callback_url,
        }
        return self._request(
            "/auth/payment_requests/address", body=body, is_user_method=True
        )

    def auth_deposit_info(self, currency: str):
        """
        Get deposit address
        https://docs.kuna.io/docs/%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B8%D1%82%D1%8C-%D0%B0%D0%B4%D1%80%D0%B5%D1%81-%D0%B4%D0%BB%D1%8F-%D0%B4%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%B0
        :param currency: like 'eth'
        :return:
        """
        body = {"currency": currency}
        return self._request("/auth/deposit/info", body=body, is_user_method=True)

    def auth_deposit(
        self, currency: str, amount: float, payment_service: str, deposit_from: str
    ):
        """
        Deposit fiat money
        https://docs.kuna.io/docs/%D0%BF%D0%BE%D0%BF%D0%BE%D0%BB%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5-%D1%84%D0%B8%D0%B0%D1%82%D0%BE%D0%BC-%D1%81-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC-%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D0%BE%D0%B3%D0%BE-%D0%BF%D0%BB%D0%B0%D1%82%D0%B5%D0%B6%D0%BD%D0%BE%D0%B3%D0%BE-%D1%81%D0%B5%D1%80%D0%B2%D0%B8%D1%81%D0%B0
        :param currency:
        :param amount:
        :param payment_service:
        :param deposit_from:
        :return:
        """
        body = {
            "currency": currency,
            "amount": amount,
            "payment_service": payment_service,
            "deposit_from": deposit_from,
        }
        return self._request("/auth/deposit", body=body, is_user_method=True)

    def auth_deposit_details(self, id: int):
        """
        Get info about deposin with given ID
        https://docs.kuna.io/docs/get-info-about-deposit
        :param id: like 581303
        :return:
        """
        body = {"id": id}
        return self._request("/auth/deposit/details", body=body, is_user_method=True)

    def auth_withdraw_prerequest(self, currency: str):
        """
        Creates withdraw pre-request
        :param currency: like 'uah'
        :return: https://docs.kuna.io/reference#postv3withdrawprerequest
        """
        body = {"currency": currency}
        return self._request(
            "/auth/withdraw/prerequest", body=body, is_user_method=True
        )

    def auth_withdraw(
        self,
        withdraw_type: str,
        amount: float,
        address: str = None,
        gateway: str = None,
        fields: dict = None,
        withdraw_to: str = None,
        fund_source_id: int = None,
        payment_id: str = None,
        allow_blank_memo: bool = None,
        withdrawall: bool = None,
    ):
        """
        Create request for withdrawal
        https://docs.kuna.io/docs/create-request-for-withdrawal
        :param withdraw_type: like 'btc' or 'uah'. 'default' for fiat to card
        :param amount: amount to withdraw. By default without fee
        :param address: for crypto withdraw
        :param gateway: for fiat withdraw
        :param withdraw_to: Credit card number
        :param fields: additional params for fiat withdraw
        :param fund_source_id: saved fiat withdraw gateway
        :param payment_id: Memo / Tag / Payment ID etc for cryptos like XRP, EOS, Stellar
        :param allow_blank_memo: should be True if payment_id is blank
        :param withdrawall: if True then amount includes fee
        :return:
        """
        body = {
            "withdraw_type": withdraw_type,
            "amount": amount,
            "address": address,
            "gateway": gateway,
            "fields": fields,
            "withdraw_to": withdraw_to,
            "fund_source_id": fund_source_id,
            "payment_id": payment_id,
            "allow_blank_memo": allow_blank_memo,
            "withdrawall": withdrawall,
        }
        return self._request("/auth/withdraw", body=body, is_user_method=True)

    def auth_withdraw_details(self, id: int):
        """
        Get withdraw details by id
        https://docs.kuna.io/docs/get-status-request-for-withdrawal
        :param id:
        :return:
        """
        body = {"id": id}
        return self._request("/auth/withdraw/details", body=body, is_user_method=True)

    def assets_history(self, type: str = None):
        """
        Info about all deposits or withdraws or both
        https://docs.kuna.io/docs/get-deposits-and-withdrawals-history
        :param type: may be 'withdraws' or 'deposits'
        :return:
        """
        if type and type.lower() not in ["withdraws", "deposits"]:
            raise APIError("type must by 'withdraws', 'deposits' or None")
        if type:
            path = f"/auth/assets-history/{type}"
        else:
            path = "/auth/assets-history"
        return self._request(path, is_user_method=True)

    def auth_merchant_deposit(
        self,
        currency: str,
        amount: float,
        return_url: str = None,
        callback_url: str = None,
    ):
        """
        Deposit using default payment service
        https://docs.kuna.io/docs/deposits-using-default-payment-service
        :param currency: like 'uah'
        :param amount:
        :param return_url:
        :param callback_url:
        :return:
        """
        body = {
            "currency": currency,
            "amount": amount,
            "payment_service": "default",
            "return_url": return_url,
            "callback_url": callback_url,
        }

        return self._request("/auth/merchant/deposit", body=body, is_user_method=True)

    def auth_merchant_payment_services(self, currency: str):
        """
        Get available payment services - gateways
        :param currency: like 'uah'
        :return:
        """
        body = {"currency": currency}
        return self._request(
            "/auth/merchant/payment_services", body=body, is_user_method=True
        )

    # KUNA CODES
    def kuna_codes_check(self, code: str):
        """
        Check kuna code by first 5 symbols of code
        :param code:
        :return: https://docs.kuna.io/reference#getv3kunacodescodecheck
        """
        return self._request(f"/kuna_codes/{code}/check")

    def kuna_codes(
        self,
        currency: str,
        amount: float,
        recipient: str = None,
        non_refundable_before: str = None,
        comment: str = None,
        private_comment: str = None,
    ):
        """
        Create Kuna code
        https://docs.kuna.io/docs/%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D1%82%D1%8C-kuna-code
        :param currency: like 'btc'
        :param amount: 0.1
        :param recipient:
        :param non_refundable_before: time in ISO-8601 "YYYY-MM-DDThh:mm:ss" - strftime('%Y-%m-%dT%H:%M:%S')
        :param comment: public comment
        :param private_comment: private comment
        :return: https://docs.kuna.io/reference#postv3authkunacodes
        """
        body = {
            "currency": currency,
            "amount": amount,
            "recipient": recipient,
            "non_refundable_before": non_refundable_before,
            "comment": comment,
            "private_comment": private_comment,
        }

        return self._request("/auth/kuna_codes", body=body, is_user_method=True)

    def auth_kuna_codes_details(self, id: int):
        """
        Info about code. Only for creator
        https://docs.kuna.io/docs/%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B8%D1%82%D1%8C-%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%86%D0%B8%D1%8E-%D0%BE-kuna-code-%D0%BF%D0%BE-id
        :param id:
        :return:
        """
        body = {"id": id}
        return self._request("/auth/kuna_codes/details", body=body, is_user_method=True)

    def auth_kuna_codes_redeem(self, code):
        """
        Activate Kuna code
        https://docs.kuna.io/docs/%D0%BF%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%B8%D1%82%D1%8C-kuna-code
        :param code: like "857ny-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX-KUN-KCode"
        :return: https://docs.kuna.io/reference#putv3authkunacodesredeem
        """
        body = {"code": code}
        return self._request("/auth/kuna_codes/redeem", body=body, is_user_method=True)

    def auth_kuna_codes_issued_by_me(
        self,
        page: int = None,
        per_page: int = None,
        order_by: str = None,
        order_dir: str = None,
        status: List[str] = None,
    ):
        """
        All kuna codes issued by user
        https://docs.kuna.io/docs/%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA-%D0%B2%D1%8B%D0%BF%D1%83%D1%89%D0%B5%D0%BD%D0%BD%D1%8B%D1%85-%D0%BA%D0%BE%D0%B4%D0%BE%D0%B2
        :param page: by default 1
        :param per_page: by default = 10
        :param order_by: order attribute: 'redeemed_at', 'amount', 'created_at' (default)
        :param order_dir: order direction: 'asc', 'desc' (default)
        :param status: filter by status: 'created', 'processing', 'active', 'redeeming', 'redeemed', 'onhold',
                       'canceled'
        :return: https://docs.kuna.io/reference#postv3authkunacodesissuedbyme
        """
        body = {
            "page": page,
            "per_page": per_page,
            "order_by": order_by,
            "order_dir": order_dir,
            "status": status,
        }
        return self._request(
            "/auth/kuna_codes/issued-by-me", body=body, is_user_method=True
        )

    def auth_kuna_codes_redeemed_by_me(
        self,
        page: int = None,
        per_page: int = None,
        order_by: str = None,
        order_dir: str = None,
    ):
        """
        All kuna codes redeemed by user
        https://docs.kuna.io/docs/%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA-%D0%B0%D0%BA%D1%82%D0%B8%D0%B2%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%BA%D0%BE%D0%B4%D0%BE%D0%B2
        :param page: by default 1
        :param per_page: by default = 10
        :param order_by: order attribute: 'created_at', 'amount','redeemed_at' (default)
        :param order_dir: order direction: 'asc', 'desc' (default)
        :return: https://docs.kuna.io/reference#postv3authkunacodesredeemedbyme
        """
        body = {
            "page": page,
            "per_page": per_page,
            "order_by": order_by,
            "order_dir": order_dir,
        }
        return self._request(
            "/auth/kuna_codes/redeemed-by-me", body=body, is_user_method=True
        )
