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

##
# CONSTANTS
##
VERSION = "1.4.0"  # should keep up with counterblockd repo's release tag

DB_VERSION = 24  # a db version increment will cause counterblockd to rebuild its database off of counterpartyd

UNIT = 100000000

MARKET_PRICE_DERIVE_NUM_POINTS = 8  # number of last trades over which to derive the market price (via WVAP)

# FROM counterpartyd
# NOTE: These constants must match those in counterpartyd/lib/py
REGULAR_DUST_SIZE = 5430
MULTISIG_DUST_SIZE = 5430 * 2
ORDER_BTC_DUST_LIMIT_CUTOFF = MULTISIG_DUST_SIZE

BTC = 'BTC'
XBTC = 'XBTC'
XCP = 'XCP'

BTC_NAME = "Bitcoin"
XCP_NAME = "Counterparty"
APP_NAME = "counterblock"
COUNTERPARTY_APP_NAME = XCP_NAME.lower()

BTC_TO_XCP = BTC + '/' + XCP
XCP_TO_BTC = XCP + '/' + BTC

MAX_REORG_NUM_BLOCKS = 10  # max reorg we'd likely ever see
MAX_FORCED_REORG_NUM_BLOCKS = 20  # but let us go deeper when messages are out of sync

QUOTE_ASSETS = [BTC, XBTC, XCP, 'PEPECASH', 'BITCRYSTALS', 'FLDC', 'RUSTBITS', 'SCOTCOIN', 'DATABITS', 'BITCORN', 'MAFIACASH']  # define the priority for quote asset
MARKET_LIST_QUOTE_ASSETS = [XCP, BTC]  # define the order in the market list

DEFAULT_BACKEND_PORT_REGTEST = 28332
DEFAULT_BACKEND_PORT_TESTNET = 18332
DEFAULT_BACKEND_PORT = 8332

DEFAULT_LOG_SIZE_KB = 20000
DEFAULT_LOG_NUM_FILES = 5

##
# STATE
##
mongo_db = None  # will be set on server init
state = {
    'caught_up': False  # atomic state variable, set to True when counterpartyd AND counterblockd are caught up
    # the rest of this is added dynamically
}


##
# METHODS
##
def get_dirs():
    import appdirs
    data_dir = appdirs.user_data_dir(appauthor=XCP_NAME, appname=APP_NAME, roaming=True)
    config_dir = appdirs.user_config_dir(appauthor=XCP_NAME, appname=APP_NAME, roaming=True)
    log_dir = appdirs.user_log_dir(appauthor=XCP_NAME, appname=APP_NAME)
    return data_dir, config_dir, log_dir


def init_base(args):
    import os
    import configparser
    import email.utils

    # testnet
    global TESTNET
    if args.testnet:
        TESTNET = args.testnet
    else:
        TESTNET = False

    global REGTEST
    if args.regtest:
        REGTEST = args.regtest
    else:
        REGTEST = False

    global net_path_part
    if TESTNET:
        net_path_part = '.testnet'
    elif REGTEST:
        net_path_part = '.regtest'
    else:
        net_path_part = ''

    # first block
    global BLOCK_FIRST
    if TESTNET:
        BLOCK_FIRST = 310000
    elif REGTEST:
        BLOCK_FIRST = 100
    else:
        BLOCK_FIRST = 278270

    global LATEST_BLOCK_INIT
    LATEST_BLOCK_INIT = {'block_index': BLOCK_FIRST, 'block_time': None, 'block_hash': None}

    # init variables used for reparse operations
    global IS_REPARSING
    IS_REPARSING = False
    global QUIT_AFTER_CAUGHT_UP
    QUIT_AFTER_CAUGHT_UP = False

    ##############
    # THINGS WE CONNECT TO

    # backend (e.g. bitcoind)
    global BACKEND_CONNECT
    if args.backend_connect:
        BACKEND_CONNECT = args.backend_connect
    else:
        BACKEND_CONNECT = 'localhost'

    global BACKEND_PORT
    if args.backend_port:
        BACKEND_PORT = args.backend_port
    else:
        if TESTNET:
            BACKEND_PORT = DEFAULT_BACKEND_PORT_TESTNET
        elif REGTEST:
            BACKEND_PORT = DEFAULT_BACKEND_PORT_REGTEST
        else:
            BACKEND_PORT = DEFAULT_BACKEND_PORT
    try:
        BACKEND_PORT = int(BACKEND_PORT)
        assert int(BACKEND_PORT) > 1 and int(BACKEND_PORT) < 65535
    except:
        raise Exception("Please specify a valid port number for the backend-port configuration parameter")

    global BACKEND_USER
    if args.backend_user:
        BACKEND_USER = args.backend_user
    else:
        BACKEND_USER = 'rpc'

    global BACKEND_PASSWORD
    if args.backend_password:
        BACKEND_PASSWORD = args.backend_password
    else:
        BACKEND_PASSWORD = 'rpcpassword'

    global BACKEND_AUTH
    BACKEND_AUTH = (BACKEND_USER, BACKEND_PASSWORD) if (BACKEND_USER and BACKEND_PASSWORD) else None

    global BACKEND_URL
    BACKEND_URL = 'http://' + BACKEND_USER + ':' + BACKEND_PASSWORD + '@' + BACKEND_CONNECT + ':' + str(BACKEND_PORT)

    global BACKEND_URL_NOAUTH
    BACKEND_URL_NOAUTH = 'http://' + BACKEND_CONNECT + ':' + str(BACKEND_PORT) + '/'

    # counterpartyd RPC connection
    global COUNTERPARTY_CONNECT
    if args.counterparty_connect:
        COUNTERPARTY_CONNECT = args.counterparty_connect
    else:
        COUNTERPARTY_CONNECT = 'localhost'

    global COUNTERPARTY_PORT
    if args.counterparty_port:
        COUNTERPARTY_PORT = args.counterparty_port
    else:
        if TESTNET:
            COUNTERPARTY_PORT = 14000
        elif REGTEST:
            COUNTERPARTY_PORT = 24000
        else:
            COUNTERPARTY_PORT = 4000
    try:
        COUNTERPARTY_PORT = int(COUNTERPARTY_PORT)
        assert int(COUNTERPARTY_PORT) > 1 and int(COUNTERPARTY_PORT) < 65535
    except:
        raise Exception("Please specify a valid port number for the counterparty-port configuration parameter")

    global COUNTERPARTY_USER
    if args.counterparty_user:
        COUNTERPARTY_USER = args.counterparty_user
    else:
        COUNTERPARTY_USER = 'rpc'

    global COUNTERPARTY_PASSWORD
    if args.counterparty_password:
        COUNTERPARTY_PASSWORD = args.counterparty_password
    else:
        COUNTERPARTY_PASSWORD = 'rpcpassword'

    global COUNTERPARTY_RPC
    COUNTERPARTY_RPC = 'http://' + COUNTERPARTY_CONNECT + ':' + str(COUNTERPARTY_PORT) + '/api/'

    global COUNTERPARTY_AUTH
    COUNTERPARTY_AUTH = (COUNTERPARTY_USER, COUNTERPARTY_PASSWORD) if (COUNTERPARTY_USER and COUNTERPARTY_PASSWORD) else None

    # mongodb
    global MONGODB_CONNECT
    if args.mongodb_connect:
        MONGODB_CONNECT = args.mongodb_connect
    else:
        MONGODB_CONNECT = 'localhost'

    global MONGODB_PORT
    if args.mongodb_port:
        MONGODB_PORT = args.mongodb_port
    else:
        MONGODB_PORT = 27017
    try:
        MONGODB_PORT = int(MONGODB_PORT)
        assert int(MONGODB_PORT) > 1 and int(MONGODB_PORT) < 65535
    except:
        raise Exception("Please specify a valid port number for the mongodb-port configuration parameter")

    global MONGODB_DATABASE
    if args.mongodb_database:
        MONGODB_DATABASE = args.mongodb_database
    else:
        if TESTNET:
            MONGODB_DATABASE = 'counterblockd_testnet'
        elif REGTEST:
            MONGODB_DATABASE = 'counterblockd_regtest'
        else:
            MONGODB_DATABASE = 'counterblockd'

    global MONGODB_USER
    if args.mongodb_user:
        MONGODB_USER = args.mongodb_user
    else:
        MONGODB_USER = None

    global MONGODB_PASSWORD
    if args.mongodb_password:
        MONGODB_PASSWORD = args.mongodb_password
    else:
        MONGODB_PASSWORD = None

    # redis-related
    global REDIS_CONNECT
    if args.redis_connect:
        REDIS_CONNECT = args.redis_connect
    else:
        REDIS_CONNECT = '127.0.0.1'

    global REDIS_PORT
    if args.redis_port:
        REDIS_PORT = args.redis_port
    else:
        REDIS_PORT = 6379
    try:
        REDIS_PORT = int(REDIS_PORT)
        assert int(REDIS_PORT) > 1 and int(REDIS_PORT) < 65535
    except:
        raise Exception("Please specify a valid port number for the redis-port configuration parameter")

    global REDIS_DATABASE
    if args.redis_database:
        REDIS_DATABASE = args.redis_database
    else:
        if TESTNET:
            REDIS_DATABASE = 1
        elif REGTEST:
            REDIS_DATABASE = 2
        else:
            REDIS_DATABASE = 0
    try:
        REDIS_DATABASE = int(REDIS_DATABASE)
        assert int(REDIS_DATABASE) >= 0 and int(REDIS_DATABASE) <= 16
    except:
        raise Exception("Please specify a valid redis-database configuration parameter (between 0 and 16 inclusive)")

    global BLOCKTRAIL_API_KEY
    BLOCKTRAIL_API_KEY = args.blocktrail_api_key or None
    global BLOCKTRAIL_API_SECRET
    BLOCKTRAIL_API_SECRET = args.blocktrail_api_secret or None

    ##############
    # THINGS WE SERVE

    global RPC_HOST
    if args.rpc_host:
        RPC_HOST = args.rpc_host
    else:
        RPC_HOST = 'localhost'

    global RPC_PORT
    if args.rpc_port:
        RPC_PORT = args.rpc_port
    else:
        if TESTNET:
            RPC_PORT = 14100
        elif REGTEST:
            RPC_PORT = 24100
        else:
            RPC_PORT = 4100
    try:
        RPC_PORT = int(RPC_PORT)
        assert int(RPC_PORT) > 1 and int(RPC_PORT) < 65535
    except:
        raise Exception("Please specify a valid port number for the rpc-port configuration parameter")

    global RPC_ALLOW_CORS
    if args.rpc_allow_cors:
        RPC_ALLOW_CORS = args.rpc_allow_cors
    else:
        RPC_ALLOW_CORS = True

    # Other things
    global SUBDIR_ASSET_IMAGES
    SUBDIR_ASSET_IMAGES = "asset_img%s" % net_path_part  # goes under the data dir and stores retrieved asset images
    global SUBDIR_FEED_IMAGES
    SUBDIR_FEED_IMAGES = "feed_img%s" % net_path_part  # goes under the data dir and stores retrieved feed images

    ##############
    # OTHER SETTINGS

    # System (logging, pids, etc)
    global COUNTERBLOCKD_DIR
    COUNTERBLOCKD_DIR = os.path.realpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))

    global LOG
    if args.log_file is False:  # no file logging
        LOG = None
    elif not args.log_file:  # default location
        LOG = os.path.join(log_dir, 'server%s.log' % net_path_part)
    else:  # user-specified location
        LOG = args.log_file

    global LOG_SIZE_KB
    if args.log_size_kb:
        LOG_SIZE_KB = args.log_size_kb
    else:
        LOG_SIZE_KB = DEFAULT_LOG_SIZE_KB
    try:
        LOG_SIZE_KB = int(LOG_SIZE_KB)
        assert LOG_SIZE_KB > 0
    except:
        raise Exception("Please specify a valid log-size-kb value (in kilobytes)")

    global LOG_NUM_FILES
    if args.log_num_files:
        LOG_NUM_FILES = args.log_num_files
    else:
        LOG_NUM_FILES = DEFAULT_LOG_NUM_FILES
    try:
        LOG_NUM_FILES = int(LOG_NUM_FILES)
        assert LOG_NUM_FILES > 0 and LOG_NUM_FILES <= 100
    except:
        raise Exception("Please specify a valid log-num-files value (must be less than 100)")

    global TX_LOG
    if args.tx_log_file is False:  # no file logging
        TX_LOG = None
    elif not args.tx_log_file:  # default location
        TX_LOG = os.path.join(log_dir, 'server%s.tx.log' % net_path_part)
    else:  # user-specified location
        TX_LOG = args.tx_log_file

    global PID
    if args.pid_file:
        PID = args.pid_file
    else:
        PID = os.path.join(data_dir, 'server%s.pid' % net_path_part)


def load_schemas():
    """initialize json schema for json asset and feed validation"""
    import os
    import json
    assert COUNTERBLOCKD_DIR

    global ASSET_SCHEMA
    ASSET_SCHEMA = json.load(open(os.path.join(COUNTERBLOCKD_DIR, 'schemas', 'asset.schema.json')))

    global FEED_SCHEMA
    FEED_SCHEMA = json.load(open(os.path.join(COUNTERBLOCKD_DIR, 'schemas', 'feed.schema.json')))


def init(args):
    #set up dirs
    global data_dir, config_dir, log_dir
    data_dir, config_dir, log_dir = get_dirs()
    assert data_dir and config_dir and log_dir

    init_base(args)
    load_schemas()