#!/usr/lib/python3/dist-packages/sylk-pushserver/bin/python
import argparse
import sys
import os

from application import log
from application.process import process

CASSANDRA_MODULES_AVAILABLE = False
try:
    from cassandra.cqlengine import columns, connection
except ImportError:
    pass
else:
    try:
        from cassandra.cqlengine.models import Model
    except ImportError:
        pass
    else:
        CASSANDRA_MODULES_AVAILABLE = True
        from cassandra import InvalidRequest
        from cassandra.cqlengine.query import LWTException
        from cassandra.cluster import Cluster, Session, NoHostAvailable, ExecutionProfile, EXEC_PROFILE_DEFAULT
        from cassandra.io import asyncioreactor
        from cassandra.policies import DCAwareRoundRobinPolicy
        from cassandra.cqlengine.management import sync_table, create_keyspace_simple

parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('-h', '--help',
                    action='help',
                    default=argparse.SUPPRESS,
                    help='Show this help message and exit.')

parser.add_argument("--config_dir",
                    default=None,
                    metavar='PATH',
                    help="Specify a config directory that contains "
                         "general.ini, applications.ini and "
                         "the credentials directory, "
                         "Default it uses '/etc/sylk-pushserver'")

options = parser.parse_args()


class colors:
    if sys.stdout.isatty():
        TGREEN = '\033[32m'
        ENDC = '\033[m'
        BOLD = '\033[1m'
    else:
        TGREEN = ''
        ENDC = ''
        BOLD = ''


class parse_level:
    def format(record):
        if record.levelname != 'INFO':
            return f'{record.levelname:<8s} '
        else:
            return f"{'  ......':<8s} "


def ask(question):
    try:
        while ( res:=input(colors.TGREEN + f"{'>>':>8s} {question} (Enter y/n) " + colors.ENDC).lower()   ) not in {"y", "n"}: pass
    except KeyboardInterrupt:
        sys.exit(1)
    if res == "y":
        return True
    return False

def bold(string):
    return colors.BOLD + string + colors.ENDC

log.Formatter.prefix_format = parse_level

if options.config_dir is not None:
    if not os.path.exists(f'{options.config_dir}'):
        log.info(f'Specified config directory {options.config_dir} does not exist')
        sys.exit(1)
    config_dir = options.config_dir

process.configuration.local_directory = config_dir
from pushserver.resources.storage.configuration import CassandraConfig, ServerConfig
from pushserver.models.cassandra import PushTokens, OpenSips

log.info(f"\n{' Sylk Pushserver - Cassandra database create/maintenance ':*^80s}\n")
log.warn('Please note, this script can potentially destroy the data in the Cassandra database.')
log.warn('Make sure you have a backup if you already have data in the Cassandra cluster')
if not ask("Would you like to continue?"):
    sys.exit()

os.environ['CQLENG_ALLOW_SCHEMA_MANAGEMENT'] = '1'

configuration = CassandraConfig.__cfgtype__(CassandraConfig.__cfgfile__)
if configuration.files:
    log.info('Reading storage configuration from {}'.format(', '.join(configuration.files)))

if CassandraConfig.table:
    PushTokens.__table_name__ = CassandraConfig.table

if CASSANDRA_MODULES_AVAILABLE:
    if CassandraConfig.cluster_contact_points:
        profile = ExecutionProfile(
            load_balancing_policy=DCAwareRoundRobinPolicy(),
            request_timeout=60
        )
        cluster = Cluster(CassandraConfig.cluster_contact_points, protocol_version=4, execution_profiles={EXEC_PROFILE_DEFAULT: profile})
        try:
            session = cluster.connect()
        except NoHostAvailable as e:
            log.warning("Can't connect to Cassandra cluster")
            sys.exit()
        else:
            connection.set_session(session)
            if CassandraConfig.keyspace in cluster.metadata.keyspaces:
                 log.info(f"Keyspace {bold(CassandraConfig.keyspace)} is already on the server.")
            else:
                log.warning(f"Keyspace {bold(CassandraConfig.keyspace)} is {bold('not')} defined on the server")
                if ask("Would you like to create the keyspace with SimpleStrategy?"):
                    create_keyspace_simple(CassandraConfig.keyspace, 1)
                else:
                    sys.exit(1)

            keyspace = cluster.metadata.keyspaces[CassandraConfig.keyspace]
            replication_strategy = keyspace.replication_strategy
            log.info(f'Server has keyspace {bold(keyspace.name)} with replication strategy: {keyspace.replication_strategy.name}')

#            if replication_strategy.name == 'NetworkTopologyStrategy':
#                for dc in replication_strategy.dc_replication_factors_info:
#                    log.info(f'DC: {dc}')

            PushTokens.__keyspace__ = CassandraConfig.keyspace
            OpenSips.__keyspace__ = CassandraConfig.keyspace
            if CassandraConfig.table in cluster.metadata.keyspaces[CassandraConfig.keyspace].tables:
                log.info(f'Table {bold(CassandraConfig.table)} is in the keyspace {bold(CassandraConfig.keyspace)}')

                if ask("Would you like to update the schema with the model?"):
                    sync_table(PushTokens)
            else:
                log.info(f'Table {bold(CassandraConfig.table)} is not the keyspace {bold(CassandraConfig.keyspace)}')

                if ask ("Would you like to create the table from the model?"):
                    sync_table(PushTokens)

            if 'mobile_devices' in cluster.metadata.keyspaces[CassandraConfig.keyspace].tables:
                log.info(f"The {bold('mobile_devices')} table is in keyspace {bold(CassandraConfig.keyspace)}")
                if ask("Would you like to update the schema with the model?"):
                    sync_table(OpenSips)
            else:
                log.warn(f"The {bold('mobile_devices')} table is {bold('not')} in keyspace {bold(CassandraConfig.keyspace)}")
                if ask("Would you like to create 'mobile-devices' table from the model?"):
                    sync_table(OpenSips)
    else:
        log.warning("Cassandra cluster contact points are not set, please adjust 'general.ini'")
        sys.exit()
else:
    log.warning('The python Cassandra drivers are not installed, please make sure they are installed')
    sys.exit()
