from parallels.core.application.drupal import DrupalModel
from parallels.core.application.joomla import JoomlaModel
from parallels.core.application.magento import MagentoModel
from parallels.core.application.prestashop import PrestashopModel
from parallels.core.application.wordpress import WordpressModel
from parallels.core.logging import get_logger
from parallels.core.utils.application_utils import get_application_models
from parallels.core.utils.common import is_empty
from parallels.core.utils.migrator_utils import get_optional_option_value
from parallels.plesk.source.web import messages
from parallels.plesk.source.web.actions.base.site_migration import SiteMigrationAction

logger = get_logger(__name__)


class RetrieveApplications(SiteMigrationAction):
    def get_description(self):
        """Get short description of action as string

        :rtype: str | unicode
        """
        return messages.ACTION_RETRIEVE_APPLICATIONS_DESCRIPTION

    def get_failure_message(self, global_context):
        """Get message for situation when action failed

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :rtype: str | unicode
        """
        return messages.ACTION_RETRIEVE_APPLICATIONS_FAILURE

    def is_critical(self):
        """If action is critical or not

        If action is critical and it failed for a subscription, migration tool
        won't run the next operations for the subscription.

        :rtype: bool
        """
        return False

    def run(self, global_context):
        """
        :type global_context: parallels.plesk.source.web.global_context.WebGlobalMigrationContext
        """
        if (
            not get_optional_option_value(global_context.options, 'reload_source_data', False) and
            global_context.site_info_storage.has_applications()
        ):
            logger.finfo(messages.ACTION_RETRIEVE_APPLICATIONS_SOURCE_CACHED)
            return

        logger.finfo(messages.ACTION_RETRIEVE_APPLICATIONS_SOURCE)

        application_paths = {}

        source = global_context.conn.get_source()

        for application_model in get_application_models(
            filter_name=[
                WordpressModel().name,
                JoomlaModel().name,
                DrupalModel().name,
                MagentoModel().name,
                PrestashopModel().name
            ]
        ):
            # search application instances
            application_instances = application_model.search(
                source, source.get_absolute_files_root(),
                global_context.site_info_storage.get_files()
            )
            if len(application_instances) == 0:
                continue

            # skip instances which have at least one invalid database
            valid_instances_paths = []
            for instance in application_instances:
                with logger.debug_level_context(
                    messages.LOOK_FOR_DATABASES_OF_APPLICATION, application_description=instance.description
                ):
                    if valid_databases(instance.get_databases()):
                        valid_instances_paths.append(instance.base_path)
            found_instances_count = len(valid_instances_paths)
            if found_instances_count == 0:
                continue

            application_paths[application_model.name] = valid_instances_paths

        global_context.site_info_storage.set_applications(application_paths)
        global_context.status_storage.update_application_list(application_paths)


def valid_databases(databases):
    """Check databases for empty fields

    :type databases: list[parallels.core.application.utils.ApplicationInstanceDatabase]
    :rtype: bool
    """
    for database in databases:
        if not valid_database(database):
            return False
    return True


def valid_database(database):
    """Check database for empty fields

    :type database: parallels.core.application.utils.ApplicationInstanceDatabase
    :rtype: bool
    """
    return (
        database is not None
        and not is_empty(database.host)
        and not is_empty(database.name)
        and not is_empty(database.username)
        and not is_empty(database.password)
    )

