# Copyright (c) 2015, JINGROW and Contributors
# License: MIT. See LICENSE
"""
	Sync's pagetype and pagefields from txt files to database
	perms will get synced only if none exist
"""
import os

import jingrow
from jingrow.cache_manager import clear_controller_cache
from jingrow.model.base_page import get_controller
from jingrow.modules.import_file import import_file_by_path
from jingrow.modules.patch_handler import _patch_mode
from jingrow.utils import update_progress_bar

IMPORTABLE_PAGETYPES = [
	("core", "pagetype"),
	("core", "page"),
	("core", "report"),
	("desk", "dashboard_chart_source"),
	("printing", "print_format"),
	("website", "web_page"),
	("website", "website_theme"),
	("website", "web_form"),
	("website", "web_template"),
	("email", "notification"),
	("printing", "print_style"),
	("desk", "workspace"),
	("desk", "onboarding_step"),
	("desk", "module_onboarding"),
	("desk", "form_tour"),
	("custom", "client_script"),
	("core", "server_script"),
	("custom", "custom_field"),
	("custom", "property_setter"),
]


def sync_all(force=0, reset_permissions=False):
	_patch_mode(True)

	for app in jingrow.get_installed_apps():
		sync_for(app, force, reset_permissions=reset_permissions)

	_patch_mode(False)

	jingrow.clear_cache()


def sync_for(app_name, force=0, reset_permissions=False):
	files = []

	if app_name == "jingrow":
		# these need to go first at time of install

		JINGROW_PATH = jingrow.get_app_path("jingrow")

		for core_module in [
			"pagefield",
			"pageperm",
			"pagetype_action",
			"pagetype_link",
			"pagetype_state",
			"role",
			"has_role",
			"pagetype",
		]:
			files.append(os.path.join(JINGROW_PATH, "core", "pagetype", core_module, f"{core_module}.json"))

		for custom_module in ["custom_field", "property_setter"]:
			files.append(
				os.path.join(JINGROW_PATH, "custom", "pagetype", custom_module, f"{custom_module}.json")
			)

		for website_module in ["web_form", "web_template", "web_form_field", "portal_menu_item"]:
			files.append(
				os.path.join(JINGROW_PATH, "website", "pagetype", website_module, f"{website_module}.json")
			)

		for desk_module in [
			"number_card",
			"dashboard_chart",
			"dashboard",
			"onboarding_permission",
			"onboarding_step",
			"onboarding_step_map",
			"module_onboarding",
			"workspace_link",
			"workspace_chart",
			"workspace_shortcut",
			"workspace_quick_list",
			"workspace_number_card",
			"workspace_custom_block",
			"workspace",
		]:
			files.append(os.path.join(JINGROW_PATH, "desk", "pagetype", desk_module, f"{desk_module}.json"))

		for module_name, document_type in IMPORTABLE_PAGETYPES:
			file = os.path.join(JINGROW_PATH, module_name, "pagetype", document_type, f"{document_type}.json")
			if file not in files:
				files.append(file)

	for module_name in jingrow.local.app_modules.get(app_name) or []:
		folder = os.path.dirname(jingrow.get_module(app_name + "." + module_name).__file__)
		files = get_pg_files(files=files, start_path=folder)

	l = len(files)

	if l:
		for i, pg_path in enumerate(files):
			import_file_by_path(
				pg_path, force=force, ignore_version=True, reset_permissions=reset_permissions
			)

			jingrow.db.commit()

			# show progress bar
			update_progress_bar(f"Updating PageTypes for {app_name}", i, l)

		# print each progress bar on new line
		print()


def get_pg_files(files, start_path):
	"""walk and sync all pagetypes and pages"""

	files = files or []

	for _module, pagetype in IMPORTABLE_PAGETYPES:
		pagetype_path = os.path.join(start_path, pagetype)
		if os.path.exists(pagetype_path):
			for pagename in os.listdir(pagetype_path):
				if os.path.isdir(os.path.join(pagetype_path, pagename)):
					pg_path = os.path.join(pagetype_path, pagename, pagename) + ".json"
					if os.path.exists(pg_path):
						if pg_path not in files:
							files.append(pg_path)

	return files


def remove_orphan_pagetypes():
	"""Find and remove any orphaned pagetypes.

	These are pagetypes for which code and schema file is
	deleted but entry is present in PageType table.

	Note: Deleting the entry doesn't delete any data.
	So this is supposed to be non-destrictive operation.
	"""

	pagetype_names = jingrow.get_all("PageType", {"custom": 0}, pluck="name")
	orphan_pagetypes = []

	clear_controller_cache()
	class_overrides = jingrow.get_hooks("override_pagetype_class", {})

	for pagetype in pagetype_names:
		if pagetype in class_overrides:
			continue
		try:
			get_controller(pagetype=pagetype)
		except ImportError:
			orphan_pagetypes.append(pagetype)
		except Exception:
			continue

	if not orphan_pagetypes:
		return

	print(f"Orphaned PageType(s) found: {', '.join(orphan_pagetypes)}")
	for i, name in enumerate(orphan_pagetypes):
		jingrow.delete_pg("PageType", name, force=True, ignore_missing=True)
		update_progress_bar("Deleting orphaned PageTypes", i, len(orphan_pagetypes))
	jingrow.db.commit()
	print()
