# -*- coding: UTF-8 -*-
#
# Copyright (C) 2014 Avencall
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>

import argparse
import logging
import xivo_dao.alchemy.all  # imports all the sqlalchemy model
from xivo_dao.alchemy.cel import CEL
from xivo_dao.alchemy.queue_log import QueueLog
from xivo_dao.alchemy.call_log import CallLog
from xivo_dao.alchemy.accesswebservice import AccessWebService
from xivo_dao.alchemy.infos import Infos
from xivo_dao.alchemy.replication_state import ReplicationState


from xivo_dao.helpers import db_manager
from xivo_dao.helpers.db_manager import Base
from xivo_db import alembic
from xivo_db import postgres

logger = logging.getLogger(__name__)

MDS_TABLES = [CallLog.__table__, CEL.__table__, QueueLog.__table__, AccessWebService.__table__, Infos.__table__, ReplicationState.__table__]

def _create_tables():
    logger.info('Creating all tables...')
    Base.metadata.create_all()

def _create_mds_tables():
    logger.info('Creating mds tables...')
    Base.metadata.create_all(tables=MDS_TABLES)

def _populate_mds():
    create_crypto_extension = 'CREATE EXTENSION IF NOT EXISTS "pgcrypto"'
    create_uuid_extension = 'CREATE EXTENSION IF NOT EXISTS "uuid-ossp"'
    generate_uuid = 'INSERT INTO "infos" VALUES (uuid_generate_v4())'
    conn = postgres.create_db_connection(db_name='asterisk')
    with conn:
        with conn.cursor() as cursor:
            cursor.execute(create_crypto_extension)
            cursor.execute(create_uuid_extension)
            cursor.execute(generate_uuid)

def _populate_db():
    logger.info('Populating database...')
    postgres.populate_db()

def _create_user(db_user, db_user_password, schema, xc, sql_extra_query=None):
    if xc:
        schema += ', xc'

    conn = postgres.create_db_connection(db_name='asterisk')
    postgres.create_user(conn, db_user, db_user_password)

    # Grant usage on schema xc
    sql_grantusage_schema = 'GRANT USAGE ON SCHEMA xc TO %s'%db_user
    # Grant rights on already created tables, sequences
    sql_select_right_on_tables = 'GRANT SELECT ON ALL TABLES IN SCHEMA %s TO %s'%(schema,db_user)
    sql_select_right_on_sequences = 'GRANT SELECT ON ALL SEQUENCES IN SCHEMA %s TO %s'%(schema,db_user)
    # Grant default rights for tables, sequences created afterward
    sql_default_privilege_on_tables = 'ALTER DEFAULT PRIVILEGES FOR ROLE asterisk IN SCHEMA %s GRANT SELECT ON TABLES TO %s'%(schema,db_user)
    sql_default_privilege_on_sequences = 'ALTER DEFAULT PRIVILEGES FOR ROLE asterisk IN SCHEMA %s GRANT SELECT ON SEQUENCES TO %s'%(schema,db_user)
    with conn:
        with conn.cursor() as cursor:
            if xc:
                cursor.execute(sql_grantusage_schema)
            cursor.execute(sql_select_right_on_tables)
            cursor.execute(sql_select_right_on_sequences)
            cursor.execute(sql_default_privilege_on_tables)
            cursor.execute(sql_default_privilege_on_sequences)
            if sql_extra_query is not None:
                cursor.execute(sql_extra_query)

def _create_user_stats(xc=True):
    db_user = 'stats'
    db_user_password = 'stats'

    _create_user(db_user, db_user_password, 'public', xc)


def _create_user_db_replic(xc=True):
    db_user = 'dbreplic'
    db_user_password = 'dbreplic'
    extra_query = 'GRANT SELECT, INSERT, UPDATE ON replication_state TO dbreplic'

    _create_user(db_user, db_user_password, 'public', xc, extra_query)

def _drop_db():
    logger.info('Dropping database...')
    postgres.drop_db()


def _init_db():
    logger.info('Initializing database...')
    postgres.init_db()
    alembic.stamp_head()
    db_manager.init_db_from_config()


def main():
    parsed_args = _parse_args()

    _init_logging(parsed_args.verbose)

    if parsed_args.drop:
        _drop_db()

    if parsed_args.init:
        _init_db()
        _create_tables()
        _populate_db()
        _create_user_stats()
        _create_user_db_replic()

    if parsed_args.initmds:
        _init_db()
        _create_mds_tables()
        _populate_mds()
        _create_user_stats(False)
        _create_user_db_replic(False)

def _parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('-v', '--verbose', action='store_true',
                        help='increase verbosity')
    parser.add_argument('--drop', action='store_true',
                        help='drop database')
    parser.add_argument('--init', action='store_true',
                        help='initialize database')
    parser.add_argument('--initmds', action='store_true',
                        help='initialize database of a media server')
    return parser.parse_args()


def _init_logging(verbose):
    logger = logging.getLogger()
    handler = logging.StreamHandler()
    handler.setFormatter(logging.Formatter('%(message)s'))
    logger.addHandler(handler)
    if verbose:
        logger.setLevel(logging.INFO)
    else:
        logger.setLevel(logging.ERROR)
