import logging
import os
import time

import mysql.connector
import psycopg2
import pymongo
import pyodbc
import redis

MONGODB_COLLECTION_NAME = "test"
MONGODB_DB_NAME = os.getenv("MONGODB_DB_NAME", "opentelemetry-tests")
MONGODB_HOST = os.getenv("MONGODB_HOST", "localhost")
MONGODB_PORT = int(os.getenv("MONGODB_PORT", "27017"))
MYSQL_DB_NAME = os.getenv("MYSQL_DB_NAME", "opentelemetry-tests")
MYSQL_HOST = os.getenv("MYSQL_HOST", "localhost")
MYSQL_PORT = int(os.getenv("MYSQL_PORT", "3306"))
MYSQL_USER = os.getenv("MYSQL_USER", "testuser")
MYSQL_PASSWORD = os.getenv("MYSQL_PASSWORD", "testpassword")
POSTGRES_DB_NAME = os.getenv("POSTGRESQL_DB_NAME", "opentelemetry-tests")
POSTGRES_HOST = os.getenv("POSTGRESQL_HOST", "localhost")
POSTGRES_PASSWORD = os.getenv("POSTGRESQL_PASSWORD", "testpassword")
POSTGRES_PORT = int(os.getenv("POSTGRESQL_PORT", "5432"))
POSTGRES_USER = os.getenv("POSTGRESQL_USER", "testuser")
REDIS_HOST = os.getenv("REDIS_HOST", "localhost")
REDIS_PORT = int(os.getenv("REDIS_PORT ", "6379"))
MSSQL_DB_NAME = os.getenv("MSSQL_DB_NAME", "opentelemetry-tests")
MSSQL_HOST = os.getenv("MSSQL_HOST", "localhost")
MSSQL_PORT = int(os.getenv("MSSQL_PORT", "1433"))
MSSQL_USER = os.getenv("MSSQL_USER", "sa")
MSSQL_PASSWORD = os.getenv("MSSQL_PASSWORD", "yourStrong(!)Password")
RETRY_COUNT = 8
RETRY_INTERVAL = 5  # Seconds

logger = logging.getLogger(__name__)


def retryable(func):
    def wrapper():
        # Try to connect to DB
        for i in range(RETRY_COUNT):
            try:
                func()
                return
            except Exception as ex:  # pylint: disable=broad-except
                logger.error(
                    "waiting for %s, retry %d/%d [%s]",
                    func.__name__,
                    i + 1,
                    RETRY_COUNT,
                    ex,
                )
            time.sleep(RETRY_INTERVAL)
        raise Exception(f"waiting for {func.__name__} failed")

    return wrapper


@retryable
def check_pymongo_connection():
    client = pymongo.MongoClient(
        MONGODB_HOST, MONGODB_PORT, serverSelectionTimeoutMS=2000
    )
    db = client[MONGODB_DB_NAME]
    collection = db[MONGODB_COLLECTION_NAME]
    collection.find_one()
    client.close()


@retryable
def check_mysql_connection():
    connection = mysql.connector.connect(
        user=MYSQL_USER,
        password=MYSQL_PASSWORD,
        host=MYSQL_HOST,
        port=MYSQL_PORT,
        database=MYSQL_DB_NAME,
    )
    connection.close()


@retryable
def check_postgres_connection():
    connection = psycopg2.connect(
        dbname=POSTGRES_DB_NAME,
        user=POSTGRES_USER,
        password=POSTGRES_PASSWORD,
        host=POSTGRES_HOST,
        port=POSTGRES_PORT,
    )
    connection.close()


@retryable
def check_redis_connection():
    connection = redis.Redis(host=REDIS_HOST, port=REDIS_PORT)
    connection.hgetall("*")


def new_mssql_connection() -> pyodbc.Connection:
    connection = pyodbc.connect(
        f"DRIVER={{ODBC Driver 17 for SQL Server}};SERVER={MSSQL_HOST},"
        f"{MSSQL_PORT};DATABASE=master;UID={MSSQL_USER};"
        f"PWD={MSSQL_PASSWORD}",
        autocommit=True,
    )
    return connection


@retryable
def check_mssql_connection():
    conn = new_mssql_connection()
    conn.close()


def setup_mssql_db():
    conn = new_mssql_connection()
    cur = conn.cursor()
    cur.execute(f"CREATE DATABASE [{MSSQL_DB_NAME}]")
    conn.close()


def check_docker_services_availability():
    # Check if Docker services accept connections
    check_pymongo_connection()
    check_mysql_connection()
    check_postgres_connection()
    check_redis_connection()
    check_mssql_connection()
    setup_mssql_db()


check_docker_services_availability()
