import glob
import mock
import psycopg2
import pytest
from tempfile import NamedTemporaryFile
from lxml import etree as ET
from lxml.etree import XMLSchema

import yatest.common

from yandex.maps.wiki import config
from yandex.maps.wiki import db
from yandex.maps.wiki import pgpool3
from maps.pylibs.local_postgres import postgres_instance
from maps.wikimap.mapspro.libs.python import cpplogger
from maps.wikimap.mapspro.services.tasks.fastcgi.lib.impl import tasks as flask_app

CATEGORIES_DIR_PATH = 'maps/wikimap/mapspro/cfg/editor'
SERVICES_BASE_TEMPLATE_PATH = 'maps/wikimap/mapspro/cfg/services/services-base-template.xml'
MIGRATIONS_PATH = 'maps/wikimap/mapspro/migrations/migrations'
SCHEMA_PATH = 'maps/wikimap/mapspro/schemas/tasks/tasks.xsd'


def init_db(conn_params):
    conn = psycopg2.connect(conn_params.connection_string)
    cursor = conn.cursor()
    cursor.execute('CREATE EXTENSION postgis')
    cursor.execute('CREATE EXTENSION hstore')
    conn.commit()


def apply_migrations(conn_params):
    files = glob.glob(yatest.common.source_path(MIGRATIONS_PATH) + "/*.sql")
    files.sort()

    conn = psycopg2.connect(conn_params.connection_string)
    cursor = conn.cursor()

    for filename in files:
        sql = open(filename).read()
        if 'NONTRANSACTIONAL' in filename:
            conn.autocommit = True
            cursor.execute(sql)
        else:
            conn.autocommit = False
            cursor.execute(sql)
            conn.commit()


@pytest.fixture(scope="session")
def postgres():
    cpplogger.init_logger()
    with postgres_instance() as conn_params:
        init_db(conn_params)
        apply_migrations(conn_params)
        yield conn_params


@pytest.fixture(scope="session")
def config_filename(postgres):
    template_filepath = yatest.common.source_path(SERVICES_BASE_TEMPLATE_PATH)
    with open(template_filepath) as template_file:
        template = template_file.read()

    config = template.replace("#DBHOST#", "localhost") \
        .replace("#DBPORT#", str(postgres.port)) \
        .replace("#DBNAME#", postgres.dbname) \
        .replace("#DBUSER#", postgres.user) \
        .replace("#DBPASS#", postgres.password) \
        .replace("#CATEGORIES_DIR_PATH#", yatest.common.source_path(CATEGORIES_DIR_PATH)) \

    with NamedTemporaryFile() as config_file:
        config_file.write(config)
        config_file.flush()
        yield config_file.name


@pytest.fixture(scope="session")
def client(config_filename):
    config.init_config(config_filename)
    db.init_pool(['core', 'validation'], role='tasks')
    pgpool3.init_pgpool(config.get_config().databases[db.CORE_DB], db.POOL_ROLE)

    flask_app.testing = True
    return flask_app.test_client()


@pytest.fixture(scope="session")
def xmlschema():
    xmlschema_doc = ET.parse(yatest.common.source_path(SCHEMA_PATH))
    return XMLSchema(xmlschema_doc)


@pytest.fixture
def clean_schema(postgres):
    conn = psycopg2.connect(postgres.connection_string)
    cursor = conn.cursor()
    cursor.execute("TRUNCATE service.validation_task RESTART IDENTITY CASCADE")
    cursor.execute("TRUNCATE service.task RESTART IDENTITY CASCADE")
    conn.commit()


@pytest.fixture(scope='function')
def grinder_class(module_name):
    class_name = 'maps.wikimap.mapspro.services.tasks.fastcgi.modules.{0}.{0}.grinder.GrinderGateway'.format(module_name)
    with mock.patch(class_name) as grinder_class:
        yield grinder_class


@pytest.fixture(scope="function")
def setup_acl_groups():
    with mock.patch("maps.wikimap.mapspro.libs.python.acl.is_member_of_group") as is_member_of_group:
        is_member_of_group.return_value = True
        yield is_member_of_group


@pytest.fixture(scope="function")
def setup_permissions():
    with mock.patch("maps.wikimap.mapspro.libs.python.acl.is_permission_granted") as is_permission_granted:
        is_permission_granted.return_value = True
        yield is_permission_granted
