import copy
import logging
import sys, os
import mysql.connector
from mysql.connector import pooling
from sqlalchemy import create_engine
from sqlalchemy.pool import NullPool
from func_timeout import func_set_timeout
from sqlalchemy.exc import OperationalError
sys.path.append(os.path.dirname(os.path.dirname(sys.path[0])))  # 上级目录
from amazon_spider.utils.common import is_internet_available


cnx_pool = None

MYSQL_connector = {
    'pool_name': 'mysql_connect_pool',
    'pool_size': 5,
    'database': 'selection',
    'host': 'rm-wz9yg9bsb2zf01ea4yo.mysql.rds.aliyuncs.com',
    'user': 'XP_Yswg2025_PY',
    'password': 'Gd1pGJog1ysLMLBdML8w81',
    'port': 3306,
    'charset': 'utf8',
    'connect_timeout': 300,
}

Mysql_arguments = {
    'user': 'XP_Yswg2025_PY',
    'password': 'Gd1pGJog1ysLMLBdML8w81',
    'host': 'rm-wz9yg9bsb2zf01ea4yo.mysql.rds.aliyuncs.com',
    'port': 3306,
    'database': 'selection',
    'charset': 'utf8',
}

keepa_mysql = {
    'user': 'root',
    'password': 'Yswg@erp120300',
    'host': '120.77.232.73',
    'port': 3306,
    'database': 'inventory_test',
    'charset': 'utf8mb4',
}

# keepa_mysql = {
#     'user': 'chenjianyun',
#     'password': 'Cjy8751_07',
#     'host': 'rm-wz956fk600d89g2g7uo.mysql.rds.aliyuncs.com',
#     'port': 3306,
#     'database': 'inventory',
#     'charset': 'utf8mb4',
# }


def sql_connect(site="us"):
    """ sql connect.

    :return: None
    """
    global cnx_pool, MYSQL_connector
    MysqlArgument = copy.deepcopy(MYSQL_connector)
    if site not in ['uk', 'fr', 'es', 'it', 'de']:
        MysqlArgument["database"] = 'selection'
    else:
        MysqlArgument["database"] = f'selection_{site}'
    try:
        cnx_pool = mysql.connector.pooling.MySQLConnectionPool(
            **MysqlArgument,
            autocommit=True,
        )
    except mysql.connector.Error as err:
        logging.info(f"mysql connector err {err}")
        if err.errno == mysql.ER_ACCESS_DENIED_ERROR:
            logging.getLogger().exception(err)
        elif err.errno == mysql.ER_BAD_DB_ERROR:
            logging.getLogger().exception(err)
        else:
            logging.getLogger().exception(err)


@func_set_timeout(60)
def sql_fetch_one(stmt, data=None, site="us"):
    """fetch one.

    :param stmt: sql statement.
    :param data: data.
    :return: results.
    """

    global cnx_pool
    results = None
    cnx = cnx_pool.get_connection()
    cur = cnx.cursor(buffered=True, dictionary=True)
    try:
        cur.execute(stmt, data)
        results = cur.fetchone()
    except Exception as err:
        logging.getLogger().exception(err)
    finally:
        try:
            cur.close()
            cnx.close()
        except Exception as e:
            logging.getLogger().exception(e)
    return results


@func_set_timeout(60)
def sql_fetch_rows(stmt, data=None, site="us"):
    """fetch many

    :param stmt: sql statement.
    :param data: data.
    :return: result.
    """

    global cnx_pool
    results = None
    cnx = cnx_pool.get_connection()
    cur = cnx.cursor(buffered=True, dictionary=True)
    try:
        cur.execute(stmt, data)
        results = cur.fetchall()
    except Exception as err:
        logging.getLogger().exception(err)
    finally:
        if cur:
            cur.close()
        if cnx:
            cnx.close()
    return results


@func_set_timeout(60)
def sql_fetch_one_cell(stmt, data=None, site="us"):
    """fetch one cell

    :param stmt: sql statement.
    :param data: data.
    :return: result
    """

    result = None
    cnx = cnx_pool.get_connection()
    cur = cnx.cursor(buffered=True)
    try:
        cur.execute(stmt, data)
        for i in cur:
            result = i[0]
            cur.close()
            return result
    except Exception as err:
        logging.getLogger().exception(err)
    finally:
        if cur:
            cur.close()
        if cnx:
            cnx.close()
    return result


def sql_update(stmt, data=None, site="us"):
    """update one.

    :param stmt: sql statement.
    :param data: data.
    :return: row count.
    """
    # data = [(), ()]
    cnx = cnx_pool.get_connection()
    cur = cnx.cursor(buffered=True)
    try:
        cur.execute(stmt, data)
        cnx.commit()
    except Exception as err:
        logging.getLogger().exception(err)
        cnx.rollback()
    finally:
        if cur:
            cur.close()
        if cnx:
            cnx.close()
    return cur.rowcount


def sql_update_many(stmt, data=None, site="us"):
    """update many

    :param stmt: sql statement.
    :param data: data.
    :return: row count.
    """
    cnx = cnx_pool.get_connection()
    cur = cnx.cursor(buffered=True)
    try:
        cur.executemany(stmt, data)
        cnx.commit()
    except Exception as err:
        logging.getLogger().exception(err)
        cnx.rollback()
    finally:
        if cur:
            cur.close()
        if cnx:
            cnx.close()
    return cur.rowcount


def sql_insert(stmt, data=None, site="us"):
    """ insert one

    :param stmt: sql statement.
    :param data: data.
    :return: last row id.
    """
    cnx = cnx_pool.get_connection()
    cur = cnx.cursor(buffered=True)
    try:
        cur.execute(stmt, data)
        cnx.commit()
    except Exception as err:
        logging.getLogger().exception(err)
        cnx.rollback()
    finally:
        if cur:
            cur.close()
        if cnx:
            cnx.close()
    return cur.lastrowid


def sql_insert_many(stmt, data=None, site="us"):
    """ insert many

    :param stmt: sql statement.
    :param data: data.
    :return: last row id.
    """
    cnx = cnx_pool.get_connection()
    cur = cnx.cursor(buffered=True)
    try:
        cur.executemany(stmt, data)
        cnx.commit()
    except Exception as err:
        logging.getLogger().exception(err)
        cnx.rollback()
    finally:
        if cur:
            cur.close()
        if cnx:
            cnx.close()
    return cur.lastrowid


@func_set_timeout(60)
def sql_delete(stmt, data=None, site="us"):
    """ insert many

    :param stmt: sql statement.
    :param data: data.
    :return: last row id.
    """
    cnx = cnx_pool.get_connection()
    cur = cnx.cursor(buffered=True)
    try:
        cur.execute(stmt, data)
        cnx.commit()
    except Exception as err:
        logging.getLogger().exception(err)
        cnx.rollback()
    finally:
        if cur:
            cur.close()
        if cnx:
            cnx.close()
    return cur.rowcount


# def test_connection():
#     try:
#         connection = cnx_pool.get_connection()
#         if connection.is_connected():
#             logging.info(f"链接正常----")
#             return True
#         else:
#             connection.close()
#             logging.info("链接失效----")
#             return False
#     except Error as e:
#         logging.info(f"链接异常----{e}")
#         return False


def get_country_engine(site_name="us"):
    sql_argument = copy.deepcopy(Mysql_arguments)
    keepa_argument = copy.deepcopy(keepa_mysql)
    if site_name not in ['uk', 'fr', 'es', 'it', 'de']:
        sql_argument["database"] = f"selection"
        db_ = 'mysql+pymysql://{}:{}@{}:{}/{}?charset={}'.format(*sql_argument.values())
    elif site_name == "keepa":
        db_ = 'mysql+pymysql://{}:{}@{}:{}/{}?charset={}'.format(*keepa_argument.values())
    else:
        sql_argument["database"] = f"selection_{site_name}"
        db_ = 'mysql+pymysql://{}:{}@{}:{}/{}?charset={}'.format(*sql_argument.values())
    engine = create_engine(db_, poolclass=NullPool, connect_args={'connect_timeout': 10})  # , pool_recycle=3600
    return engine


def get_con(site_name="us"):
    sql_argument = copy.deepcopy(Mysql_arguments)
    keepa_argument = copy.deepcopy(keepa_mysql)
    if site_name not in ['uk', 'fr', 'es', 'it', 'de']:
        sql_argument["database"] = f"selection"
        db_ = 'mysql+pymysql://{}:{}@{}:{}/{}?charset={}'.format(*sql_argument.values())
    elif site_name == "keepa":
        db_ = 'mysql+pymysql://{}:{}@{}:{}/{}?charset={}'.format(*keepa_argument.values())
    else:
        sql_argument["database"] = f"selection_{site_name}"
        db_ = 'mysql+pymysql://{}:{}@{}:{}/{}?charset={}'.format(*sql_argument.values())
    engine = create_engine(db_, poolclass=NullPool, connect_args={'connect_timeout': 10})
    conn = engine.connect()
    return conn


@func_set_timeout(300)
def del_pg_asin(sql, site="us"):
    try:
        if not is_internet_available():
            return False
        e = get_pg_country_engine(site)
        with e.connect() as conn:
            conn.execute(sql)
            e.dispose()
            # conn.commit()
            # conn.close()
            return True
    except OperationalError as e:
        logging.info(f"失败sql为 {sql} {e}")
        return False


@func_set_timeout(30)
def del_mysql_asin(sql, data=None, site="us"):
    try:
        if not is_internet_available():
            return False
        e = get_country_engine(site)
        with e.connect() as conn:
            if data != None:
                if data:
                    conn.execute(sql, data)
            else:
                conn.execute(sql)
            e.dispose()
            # conn.commit()
            # conn.close()
            return True
    except OperationalError as e:
        return False


@func_set_timeout(300)
def df_to_sql(table_name, df, site="us", db="mysql"):
    try:
        if db == "mysql":
            e = get_country_engine(site)
        elif db == "pg":
            e = get_pg_country_engine(site)
        elif db == "pg14":
            e = get_14pg_country_engine(site)
        if is_internet_available():
            df.to_sql(name=table_name, con=e, if_exists='append', index=False)
            e.dispose()
            return True
        else:
            return False
    except OperationalError as e:
        logging.info(f"save error {e}")
        return False