from __future__ import unicode_literals

import frappe
import os
from frappe.database.db_manager import DbManager

expected_settings_10_2_earlier = {
	#"innodb_file_format": "Barracuda",
	#"innodb_file_per_table": "ON",
	#"innodb_large_prefix": "ON",
	#"character_set_server": "utf8mb4",
	#"collation_server": "utf8mb4_unicode_ci"
}

expected_settings_10_3_later = {
	#"character_set_server": "utf8mb4",
	#"collation_server": "utf8mb4_unicode_ci"
}


def get_mariadb_versions():
	# MariaDB classifies their versions as Major (1st and 2nd number), and Minor (3rd number)
	# Example: Version 10.3.13 is Major Version = 10.3, Minor Version = 13
	mariadb_variables = frappe._dict(frappe.db.sql("""show variables"""))
	version_string = mariadb_variables.get('version').split('-')[0]
	versions = {}
	versions['major'] = version_string.split(
		'.')[0] + '.' + version_string.split('.')[1]
	versions['minor'] = version_string.split('.')[2]
	return versions


def setup_database(force, source_sql, verbose, no_mariadb_socket=False):
	frappe.local.session = frappe._dict({'user':'Administrator'})

	db_name = frappe.local.conf.db_name
	root_conn = get_root_connection(frappe.flags.root_login, frappe.flags.root_password)
	dbman = DbManager(root_conn)
	if force or (db_name not in dbman.get_database_list()):
		dbman.delete_user(db_name)
		if no_mariadb_socket:
			dbman.delete_user(db_name, host="%")
		dbman.drop_database(db_name)
	else:
		raise Exception("Database %s already exists" % (db_name,))

	dbman.create_user(db_name, frappe.conf.db_password)
	if no_mariadb_socket:
		dbman.create_user(db_name, frappe.conf.db_password, host="%")
	if verbose: print("Created user %s" % db_name)

	dbman.create_database(db_name)
	if verbose: print("Created database %s" % db_name)

	dbman.grant_all_privileges(db_name, db_name)
	if no_mariadb_socket:
		dbman.grant_all_privileges(db_name, db_name, host="%")
	dbman.flush_privileges()
	if verbose: print("Granted privileges to user %s and database %s" % (db_name, db_name))

	# close root connection
	root_conn.close()

	bootstrap_database(db_name, verbose, source_sql)

def setup_help_database(help_db_name):
	dbman = DbManager(get_root_connection(frappe.flags.root_login, frappe.flags.root_password))
	dbman.drop_database(help_db_name)

	# make database
	if not help_db_name in dbman.get_database_list():
		try:
			dbman.create_user(help_db_name, help_db_name)
		except Exception as e:
			# user already exists
			if e.args[0] != 1396: raise
		dbman.create_database(help_db_name)
		dbman.grant_all_privileges(help_db_name, help_db_name)
		dbman.flush_privileges()

def drop_user_and_database(db_name, root_login, root_password):
	frappe.local.db = get_root_connection(root_login, root_password)
	dbman = DbManager(frappe.local.db)
	dbman.delete_user(db_name, host="%")
	dbman.delete_user(db_name)
	dbman.drop_database(db_name)

def bootstrap_database(db_name, verbose, source_sql=None):
	import sys

	frappe.connect(db_name=db_name)
	if not check_database_settings():
		print('Database settings do not match expected values; stopping database setup.')
		sys.exit(1)
	import_db_from_sql(source_sql, verbose)

	frappe.connect(db_name=db_name)
	if 'tabDefaultValue' not in frappe.db.get_tables():
		from click import secho

		secho(
			"Table 'tabDefaultValue' missing in the restored site. "
			"Database not installed correctly, this can due to lack of "
			"permission, or that the database name exists. Check your mysql"
			" root password, validity of the backup file or use --force to"
			" reinstall",
			fg="red"
		)
		sys.exit(1)

def import_db_from_sql(source_sql=None, verbose=False):
	if verbose: print("Starting database import...")
	db_name = frappe.conf.db_name
	if not source_sql:
		source_sql = os.path.join(os.path.dirname(__file__), 'framework_mariadb.sql')
	DbManager(frappe.local.db).restore_database(db_name, source_sql, db_name, frappe.conf.db_password)
	if verbose: print("Imported from database %s" % source_sql)


def check_database_settings():
	versions = get_mariadb_versions()
	if versions['major'] <= '10.2':
		expected_variables = expected_settings_10_2_earlier
	else:
		expected_variables = expected_settings_10_3_later

	mariadb_variables = frappe._dict(frappe.db.sql("""show variables"""))
	# Check each expected value vs. actuals:
	result = True
	for key, expected_value in expected_variables.items():
		if mariadb_variables.get(key) != expected_value:
			print("For key %s. Expected value %s, found value %s" %
				  (key, expected_value, mariadb_variables.get(key)))
			result = False
	if not result:
		site = frappe.local.site
		msg = ("Creation of your site - {x} failed because MariaDB is not properly {sep}"
			   "configured.  If using version 10.2.x or earlier, make sure you use the {sep}"
			   "the Barracuda storage engine. {sep}{sep}"
			   "Please verify the settings above in MariaDB's my.cnf.  Restart MariaDB.  And {sep}"
			   "then run `bench new-site {x}` again.{sep2}"
			   "").format(x=site, sep2="\n"*2, sep="\n")
		print_db_config(msg)
	return result


def get_root_connection(root_login, root_password):
	import getpass
	if not frappe.local.flags.root_connection:
		if not root_login:
			root_login = 'root'

		if not root_password:
			root_password = frappe.conf.get("root_password") or None

		if not root_password:
			root_password = getpass.getpass("MySQL root password: ")

		frappe.local.flags.root_connection = frappe.database.get_db(user=root_login, password=root_password)

	return frappe.local.flags.root_connection


def print_db_config(explanation):
	print("="*80)
	print(explanation)
	print("="*80)
