<?php declare(strict_types = 1);

namespace idoit\Module\SyneticsFlows\Automation;

use Exception;
use idoit\Module\SyneticsFlows\Automation\Action\ExecutionFactory\ApiCallFactory;
use idoit\Module\SyneticsFlows\Automation\Action\ExecutionFactory\CollectionExecutionFactory;
use idoit\Module\SyneticsFlows\Automation\Action\ExecutionFactory\CreateObjectFactory;
use idoit\Module\SyneticsFlows\Automation\Action\ExecutionFactory\PlanExecutionFactory;
use idoit\Module\SyneticsFlows\Automation\Action\ExecutionFactory\ProcessCategoryChanges;
use idoit\Module\SyneticsFlows\Automation\Action\ExecutionFactory\SendEmailFactory;
use idoit\Module\SyneticsFlows\Automation\Action\ExecutionFactory\UpdateDataFactory;
use idoit\Module\SyneticsFlows\Automation\Action\PerformExecution\ApplyCategoryChanges;
use idoit\Module\SyneticsFlows\Automation\Action\PerformExecution\CollectionExecution;
use idoit\Module\SyneticsFlows\Automation\Action\PerformExecution\CreateObjectExecution;
use idoit\Module\SyneticsFlows\Automation\Action\PerformExecution\PerformApiCallExecution;
use idoit\Module\SyneticsFlows\Automation\Action\PerformExecution\PlannedExecution;
use idoit\Module\SyneticsFlows\Automation\Action\PerformExecution\SendEmailExecution;
use idoit\Module\SyneticsFlows\Automation\Action\PerformExecution\ValidateCategoryChanges;
use idoit\Module\SyneticsFlows\Automation\Trigger\ConditionBuilder\CmdbConditionBuilder;
use idoit\Module\SyneticsFlows\Automation\Action\PerformExecution\UpdateDataExecution;
use idoit\Module\SyneticsFlows\Automation\Trigger\ConditionMatcher\AndConditionMatcher;
use idoit\Module\SyneticsFlows\Automation\Trigger\ConditionMatcher\ArrayConditionMatcher;
use idoit\Module\SyneticsFlows\Automation\Trigger\ConditionMatcher\ObjectBasedConditionMatcher;
use idoit\Module\SyneticsFlows\Automation\Trigger\ConditionMatcher\OrConditionMatcher;
use idoit\Module\SyneticsFlows\Automation\Trigger\ConditionMatcher\TimeConditionMatcher;
use idoit\Module\SyneticsFlows\Automation\Trigger\ConditionMatcher\UserConditionMatcher;
use idoit\Module\SyneticsFlows\Automation\Trigger\InvocationMatcher\ButtonInvocationMatcher;
use idoit\Module\SyneticsFlows\Automation\Trigger\InvocationMatcher\CategoryCreatedMatcher;
use idoit\Module\SyneticsFlows\Automation\Trigger\InvocationMatcher\CategoryEntryRankedMatcher;
use idoit\Module\SyneticsFlows\Automation\Trigger\InvocationMatcher\CategoryUpdatedMatcher;
use idoit\Module\SyneticsFlows\Automation\Trigger\InvocationMatcher\CollectionMatcher;
use idoit\Module\SyneticsFlows\Automation\Trigger\InvocationMatcher\ObjectCreatedMatcher;
use idoit\Module\SyneticsFlows\Automation\Trigger\InvocationMatcher\ObjectPurgedMatcher;
use idoit\Module\SyneticsFlows\Automation\Trigger\InvocationMatcher\ObjectRecycledMatcher;
use idoit\Module\SyneticsFlows\Automation\Trigger\InvocationMatcher\ObjectUpdatedMatcher;
use idoit\Module\SyneticsFlows\Automation\Trigger\InvocationMatcher\ObjectRankedMatcher;
use idoit\Module\SyneticsFlows\Automation\Trigger\InvocationMatcher\TimeInvocationMatcher;
use idoit\Module\SyneticsFlows\Model\AutomationDao;
use idoit\Module\SyneticsFlows\Model\CategoryDao;
use idoit\Module\SyneticsFlows\Model\CiObjectDao;
use idoit\Module\SyneticsFlows\Model\ExecutionDao;
use idoit\Module\SyneticsFlows\Session\UserSwitcher;
use idoit\Module\SyneticsFlows\Template\TemplateFactory;
use idoit\Module\SyneticsFlows\Model\ScheduleDao;
use isys_application;
use isys_cmdb_dao_category_s_person_assigned_groups;
use isys_component_database;
use isys_component_session;

class TriggerFacade
{
    public static function getService(): TriggerService
    {
        $database = isys_application::instance()->container->get('database');
        if (!$database instanceof isys_component_database) {
            throw new Exception('Incorrect configuration');
        }

        $session = isys_application::instance()->container->get('session');
        if (!$session instanceof isys_component_session) {
            throw new Exception('There is no session which can be used.');
        }

        $automationDao = new AutomationDao($database);
        $executionDao = self::getExecutionDao();
        $conditionMatcher = new ArrayConditionMatcher();
        $conditionMatcher->add(new AndConditionMatcher($conditionMatcher));
        $conditionMatcher->add(new OrConditionMatcher($conditionMatcher));
        $conditionMatcher->add(new TimeConditionMatcher());
        $conditionMatcher->add(new UserConditionMatcher(new isys_cmdb_dao_category_s_person_assigned_groups($database)));
        $conditionMatcher->add(
            new ObjectBasedConditionMatcher(new CmdbConditionBuilder($database), new CiObjectDao($database))
        );
        $categoryDao = new CategoryDao($database);
        $matcher = new CollectionMatcher([
            new ButtonInvocationMatcher($automationDao),
            new ObjectCreatedMatcher($automationDao),
            new ObjectUpdatedMatcher($automationDao),
            new ObjectRankedMatcher($automationDao),
            new ObjectRecycledMatcher($automationDao),
            new CategoryEntryRankedMatcher($automationDao),
            new CategoryCreatedMatcher($automationDao),
            new TimeInvocationMatcher(new ScheduleDao($database)),
            new CategoryUpdatedMatcher($automationDao),
            new ObjectPurgedMatcher($automationDao),
        ], $conditionMatcher);
        $template = new TemplateFactory();
        $processChanges = new ProcessCategoryChanges();
        $baseFactory = new CollectionExecutionFactory([
            new CreateObjectFactory($template, $processChanges),
            new ApiCallFactory($template),
            new UpdateDataFactory($template, $processChanges),
            new SendEmailFactory($template),
        ]);
        $factory = new CollectionExecutionFactory([
            new PlanExecutionFactory(),
            $baseFactory
        ]);
        $applyChanges = new ApplyCategoryChanges($categoryDao, $database);
        $validateChanges = new ValidateCategoryChanges($categoryDao, $database);
        $baseRunner = new CollectionExecution([
            new CreateObjectExecution($applyChanges, $validateChanges),
            new PerformApiCallExecution(),
            new SendEmailExecution(),
            new UpdateDataExecution($applyChanges, $validateChanges),
        ]);
        $runner = new CollectionExecution([
            new PlannedExecution($automationDao, $baseFactory, $baseRunner),
            $baseRunner
        ]);

        $userSwithcer = new UserSwitcher(
            $session,
            $database
        );

        return new TriggerService($matcher, $executionDao, $factory, $runner, $userSwithcer);
    }

    public static function getExecutionDao(): ExecutionDao
    {
        $database = isys_application::instance()->container->get('database');
        if (!$database instanceof isys_component_database) {
            throw new Exception('Incorrect configuration');
        }
        return new ExecutionDao($database);
    }
}
