<?php

namespace XF\Admin\Controller;

use XF\Import\Importer\AbstractCoreImporter;
use XF\Import\Importer\AbstractImporter;
use XF\Import\Manager;
use XF\Import\Runner;
use XF\Import\Session;
use XF\Import\StepState;
use XF\Job\Atomic;
use XF\Mvc\ParameterBag;

class ImportController extends AbstractController
{
	protected function preDispatchController($action, ParameterBag $params)
	{
		$this->assertAdminPermission('import');
	}

	public function actionIndex()
	{
		$manager = $this->getImportManager();

		$session = $manager->getCurrentSession();
		if ($session)
		{
			$importer = $manager->getImporter($session->importerId);
			if ($importer)
			{
				$this->triggerSessionRedirect($session);

				$viewParams = [
					'title' => $importer->getSourceTitle(),
				];
				return $this->view('XF:Import\Restart', 'import_restart', $viewParams);
			}
		}

		$viewParams = [
			'importersGrouped' => $manager->getImporterListTargetGrouped(),
			'complete' => $this->filter('complete', 'bool'),
		];
		return $this->view('XF:Import\Index', 'import_index', $viewParams);
	}

	public function actionCancel()
	{
		$this->assertPostOnly();

		$this->getImportManager()->clearCurrentSession();

		return $this->redirect($this->buildLink('import'));
	}

	public function actionConfig()
	{
		$this->assertPostOnly();

		$manager = $this->getImportManager();
		$importerId = $this->filter('importer', 'str');
		$importer = $manager->getImporter($importerId);

		if (!$importer)
		{
			return $this->redirect($this->buildLink('import'));
		}

		$previousConfig = $this->filter('previous_config', 'json-array');
		$newConfig = $this->filter('config', 'array');
		$baseConfig = array_replace_recursive($previousConfig, $newConfig);

		if ($baseConfig)
		{
			$baseConfig = $importer->prepareBaseConfigFromInput($baseConfig, $this->request);

			$configErrors = [];
			if ($importer->validateBaseConfig($baseConfig, $configErrors))
			{
				return $this->displayStepConfig($importerId, $importer, $baseConfig);
			}
			else if ($configErrors)
			{
				return $this->error($configErrors);
			}
		}

		$viewParams = [
			'importerId' => $importerId,
			'title' => $importer->getSourceTitle(),
			'importer' => $importer,
			'baseConfig' => $baseConfig,
		];
		return $this->view('XF:Import\Config', 'import_config', $viewParams);
	}

	protected function displayStepConfig(
		$importerId,
		AbstractImporter $importer,
		array $baseConfig
	)
	{
		$manager = $this->getImportManager();
		$importer->setBaseConfig($baseConfig);

		$availableSteps = $importer->getSteps();

		$steps = $this->filter('steps', 'array-str');
		if ($steps)
		{
			$steps = $manager->resolveStepDependencies($steps, $availableSteps);

			$retainIds = $this->filter('retain_ids', 'bool');
			$logTable = $this->filter('log_table', 'str');

			if ($this->filter('steps_configured', 'bool'))
			{
				$stepConfig = $this->filter('step_config', 'array');
				$stepConfig['_retainIds'] = $retainIds;
				$stepConfig = $importer->prepareStepConfigFromInput($stepConfig, $this->request);

				$configErrors = [];
				if ($importer->validateStepConfig($steps, $stepConfig, $configErrors))
				{
					$manager->initializeNewImport(
						$importerId,
						$logTable,
						$retainIds,
						$baseConfig,
						$stepConfig,
						$steps
					);
					return $this->redirect($this->buildLink('import/start'));
				}
				else if ($configErrors)
				{
					return $this->error($configErrors);
				}
			}
			else
			{
				$log = $manager->getLog($logTable);
				if ($log->isValidTable())
				{
					if (!$log->isEmpty())
					{
						return $this->error(\XF::phrase('log_table_is_valid_but_it_must_not_contain_content_enter_different_name'));
					}
				}
				else if (!$log->canInitialize($logError))
				{
					return $this->error($logError);
				}
			}

			$viewParams = [
				'importerId' => $importerId,
				'title' => $importer->getSourceTitle(),
				'importer' => $importer,
				'baseConfig' => $baseConfig,
				'retainIds' => $retainIds,
				'logTable' => $logTable,
				'steps' => $steps,
				'availableSteps' => $availableSteps,
			];
			return $this->view('XF:Import\StepConfig', 'import_step_config', $viewParams);
		}
		else
		{
			$canRetainIds = $importer->canRetainIds();
			$logTable = $importer->getSuggestedLogTableName();

			$viewParams = [
				'importerId' => $importerId,
				'title' => $importer->getSourceTitle(),
				'isCoreImporter' => $importer instanceof AbstractCoreImporter,
				'importer' => $importer,
				'baseConfig' => $baseConfig,
				'canRetainIds' => $canRetainIds,
				'logTable' => $logTable,
				'availableSteps' => $availableSteps,
			];
			return $this->view('XF:Import\StepChoose', 'import_step_choose', $viewParams);
		}
	}

	public function actionStepConfig()
	{
		$this->assertPostOnly();

		$manager = $this->getImportManager();
		$importerId = $this->filter('importer', 'str');
		$importer = $manager->getImporter($importerId);

		if (!$importer)
		{
			return $this->redirect($this->buildLink('import'));
		}

		$config = $this->filter('config', 'json-array');

		return $this->displayStepConfig($importerId, $importer, $config);
	}

	public function actionStart()
	{
		$manager = $this->getImportManager();
		$session = $manager->getCurrentSession();
		if (!$session)
		{
			return $this->redirect($this->buildLink('import'));
		}

		$this->triggerSessionRedirect($session);

		$viewParams = [
			'title' => $manager->getImporterSourceTitle($session->importerId),
		];
		return $this->view('XF:Import\Start', 'import_start', $viewParams);
	}

	public function actionRun()
	{
		if (!$this->isPost())
		{
			return $this->redirect($this->buildLink('import'));
		}

		$manager = $this->getImportManager();
		$runner = $manager->getRunner();
		if (!$runner)
		{
			return $this->redirect($this->buildLink('import'));
		}

		$session = $runner->getSession();

		$this->triggerSessionRedirect($session);

		if (!$session->canRunVia('web') && !$this->filter('force_run', 'bool'))
		{
			return $this->error(\XF::phrase('this_import_has_been_started_through_another_method'));
		}

		$this->setViewOption('force_page_template', 'PAGE_RUN_JOB');

		$runResult = $runner->run();

		$session->runType = 'web';

		$manager->updateCurrentSession($session);

		//echo \XF::app()->debugger()->getDebugPageHtml(\XF::app()); exit;

		if ($runResult == Runner::STATE_COMPLETE)
		{
			return $this->redirect($this->buildLink('import/finalize'));
		}

		$lastRun = $runner->getLastRun();

		/** @var StepState $state */
		$state = $lastRun['state'];

		$viewParams = [
			'title' => $runner->getImporter()->getSourceTitle(),
			'stepTitle' => $state->title,
			'stepComplete' => $state->complete,
			'stepCompletion' => $state->getCompletionOutput(),
			'importCompletion' => $runner->getImportCompletionDetails(),
		];
		return $this->view('XF:Import\Run', 'import_run', $viewParams);
	}

	public function actionFinalize()
	{
		$manager = $this->getImportManager();
		$session = $manager->getCurrentSession();
		if (!$session || !$session->runComplete)
		{
			return $this->redirect($this->buildLink('import'));
		}

		if ($session->finalized)
		{
			return $this->redirect($this->buildLink('import/complete'));
		}

		$importer = $manager->getImporter($session->importerId);
		if (!$importer)
		{
			$manager->clearCurrentSession();

			return $this->redirect($this->buildLink('import'));
		}

		if ($this->isPost())
		{
			$jobs = $importer->getFinalizeJobs($session->getStepsRun());
			if ($jobs)
			{
				$this->app->jobManager()->enqueueUnique(
					'importFinalize' . $session->logTable,
					Atomic::class,
					['execute' => $jobs]
				);
			}

			$session->finalized = true;
			$manager->updateCurrentSession($session);

			return $this->redirect($this->buildLink('import/finalize'));
		}
		else
		{
			$viewParams = [
				'title' => $importer->getSourceTitle(),
				'notes' => $this->getNotesData($importer, $session, 'finalize'),
			];
			return $this->view('XF:Import\Finalize', 'import_finalize', $viewParams);
		}
	}

	public function actionComplete()
	{
		$manager = $this->getImportManager();
		$session = $manager->getCurrentSession();
		if (!$session || !$session->finalized)
		{
			return $this->redirect($this->buildLink('import'));
		}

		$importer = $manager->getImporter($session->importerId);
		if (!$importer)
		{
			$manager->clearCurrentSession();

			return $this->redirect($this->buildLink('import'));
		}

		if ($this->isPost())
		{
			$manager->clearCurrentSession();

			return $this->redirect($this->buildLink('import', null, ['complete' => 1]));
		}
		else
		{
			$viewParams = [
				'title' => $importer->getSourceTitle(),
				'notes' => $this->getNotesData($importer, $session, 'complete'),
			];
			return $this->view('XF:Import\Complete', 'import_complete', $viewParams);
		}
	}

	protected function getNotesData(
		AbstractImporter $importer,
		Session $session,
		$context
	)
	{
		return $this->getImportManager()->getImportNotesData($context, $session);
	}

	/**
	 * @return Manager
	 */
	protected function getImportManager()
	{
		return $this->app->import()->manager();
	}

	protected function triggerSessionRedirect(Session $session)
	{
		if ($session->finalized)
		{
			throw $this->exception(
				$this->redirect($this->buildLink('import/complete'))
			);
		}
		if ($session->runComplete)
		{
			throw $this->exception(
				$this->redirect($this->buildLink('import/finalize'))
			);
		}
	}
}
