<?php
$_db_migration_to = '40.06'; // 9.0.0-beta
if (!isset($migrations) || !is_object($migrations))
	die("This file cannot be executed directly");
$migrations->CheckValid($_db_migration_to);
//===========================================================================================



$migrations->Run('2021-12-06_01_appdata_migration.php', <<<'DB_UPDATE_FILE'
<?php
/** @var \Claromentis\Setup\SetupFacade $migrations */

use Claromentis\Core\Config\LayeredConfig;
use Claromentis\Core\Services;

$filesystemUtil = Services::I()->GetFilesystemUtil();

/** @var LayeredConfig $config */
$config = $migrations->GetConfigFull();
$logger = $migrations->getLogger();
$cfg_cdn_type = $config->get('cfg_cdn_type');
$data = $config->get('DATA_DIR');
$web = Services::I()->{'core.web_path'};

$logger->debug("APPDATA: {$config->get('APPDATA')}");
$logger->debug("DATA_DIR: $data");
$logger->debug("core.web_path: $web");
$logger->debug("cfg_cdn_type: $cfg_cdn_type");
$logger->debug('cfg_cdn_options: ' . json_encode($config->get('cfg_cdn_options')));
$logger->debug('CLARO_CDN_OPTIONS: ' . json_encode($config->get('CLARO_CDN_OPTIONS')));

// If the CDN configuration is remote (Google, AWS S3) we don't need to do anything
$isRemoteCdnConfig = in_array($cfg_cdn_type, ['google', 'amazon']);
$logger->debug('Remote CDN config: ' . json_encode($isRemoteCdnConfig));

if ($isRemoteCdnConfig) {
	$logger->notice("CDN configuration is remote ('$cfg_cdn_type'), no appdata migration needed; appdata should already be in 'data/cdn_mirror'");
	return;
}

// If CDN config comes from the default provider (config_default.php), we can assume that we're upgrading from a system
// that uses web/appdata as a local CDN (previous default configuration)
$isLocalCdnConfig = in_array($cfg_cdn_type, ['local', 'filesystem']);
$isDefaultCdnConfig =
	$config->whereIsWithout('cfg_cdn_type', 'local') === 'default'
	&& $config->whereIsWithout('cfg_cdn_options', 'local') === 'default';

$logger->debug('Local CDN config: ' . json_encode($isLocalCdnConfig));
$logger->debug('Default CDN config: ' . json_encode($isDefaultCdnConfig));

// We also want to resolve DATA_DIR to a local path
$data = $filesystemUtil->realpath($data);
$logger->debug("DATA_DIR (realpath): $data");

if ($isDefaultCdnConfig) {
	// 0. Check appdata
	$appdata = "$web/appdata";
	$cdn_mirror = "$data/cdn_mirror";

	$logger->info("Default CDN configuration found: assuming appdata path '$appdata'");

	// If appdata doesn't exist, we should assume it has already been moved
	if (!is_dir($appdata)) {
		$logger->notice("'$appdata' does not exist, no appdata migration needed");
		return;
	}

	// If it exists, but it's not readable, then we have a problem
	if (!is_readable($appdata)) {
		$logger->error("'$appdata' is not readable, please fix file system permissions and rerun this migration");
		throw new RuntimeException("Unreadable appdata directory '$appdata'");
	}

	// 1. Back up data/cdn_mirror if it exists
	$filesystem = $migrations->getFilesystem();

	if ($filesystem->IsDir('data/cdn_mirror')) {
		$timestamp = date('Y-m-d_H-i-s');
		$backupPath = "data/backups/cdn_mirror_$timestamp";

		$logger->notice("Backing up 'data/cdn_mirror' to '$backupPath'");
		$filesystem->Rename('data/cdn_mirror', $backupPath);
	}

	// 2. Move web/appdata to data/cdn_mirror
	$logger->notice("Moving appdata from '$appdata' to '$cdn_mirror'");
	rename($appdata, "$cdn_mirror");

	// 3. Verify
	if (!is_dir("$cdn_mirror")) {
		$logger->error("Error moving appdata from '$appdata' to '$cdn_mirror'");
		throw new RuntimeException("Appdata migration failed");
	}
} else if ($isLocalCdnConfig) {
	$cfg_cdn_options = $config->get('cfg_cdn_options');
	$local_path = $cfg_cdn_options['local_path'];

	$logger->warning("Local CDN configured to path '$local_path' and cannot safely be moved automatically");
	$logger->warning("It is highly recommended to move appdata to '$data/appdata' and remove CDN configuration");
	return;
} else {
	$logger->error('CDN is misconfigured. Please remove CDN configuration and rerun migrations.');
	throw new RuntimeException("Unexpected CDN configuration type '$cfg_cdn_type'");
}

DB_UPDATE_FILE
);


$migrations->Run('2021-12-06_02_cdn_mirror_migration.php', <<<'DB_UPDATE_FILE'
<?php
/** @var \Claromentis\Setup\SetupFacade $migrations */

use Claromentis\Core\Config\LayeredConfig;
use Claromentis\Core\Filesystem\Exception\FileExistsException;
use Claromentis\Core\Filesystem\Exception\FileNotFoundException;
use Claromentis\Core\Filesystem\Exception\FilesystemException;
use Claromentis\Core\Services;

/** @var LayeredConfig $config */
$config = $migrations->GetConfigFull();
$logger = $migrations->getLogger();
$filesystem = $migrations->getFilesystem();
$data = $config->get('DATA_DIR');
$web = Services::I()->{'core.web_path'};

// Check for non-default local configuration, bail with warnings if so
$cfg_cdn_type = $config->get('cfg_cdn_type');
$isLocalCdnConfig = in_array($cfg_cdn_type, ['local', 'filesystem']);
$isDefaultCdnConfig =
	$config->whereIsWithout('cfg_cdn_type', 'local') === 'default'
	&& $config->whereIsWithout('cfg_cdn_options', 'local') === 'default';

if (!$isDefaultCdnConfig && $isLocalCdnConfig) {
	$logger->warning("Non-default local CDN configuration detected; skipping 'data/cdn_mirror' -> 'data/appdata' migration");
	$logger->warning("It is highly recommended to move appdata to '$data/appdata' and remove CDN configuration");
	return;
}

// If data/cdn_mirror doesn't exist then we must assume that it's already been
// moved across to data/appdata
if (!$filesystem->IsDir('data/cdn_mirror')) {
	$logger->notice("'data/cdn_mirror' not found, no migration to data/appdata needed");
	return;
}

// If we got this far, then all user data should be safely in the data directory
// and appdata should now exist at data/cdn_mirror.
// This is because either:
// - The previous migration moved web/appdata to data/cdn_mirror
// - Appdata was already in data/cdn_mirror due to remote CDN config

// First, let's clear all asset caches. Even though this has already been done
// by CLC, we may have some ongoing web traffic during migration which may be
// creating assets at the new default directory (data/appdata/assets_cache).
// Time to make our best effort.
$web_assets_cache = "$web/appdata/assets_cache";
$data_assets_cache = "$data/appdata/assets_cache";
rmdir_r($web_assets_cache);
rmdir_r($data_assets_cache);

// Now we want to make sure data/appdata is empty. If it isn't, we'll try the move anyway.
if ($filesystem->IsDir('data/appdata') && empty($filesystem->ListContents('data/appdata'))) {
	try {
		$filesystem->Delete('data/appdata');
	} catch (FilesystemException $exception) {
		$logger->warning("Filesystem error when removing target directory 'data/appdata'. Attempting migration anyway.");
	}
}

// Move data/cdn_mirror to data/appdata
try {
	$logger->notice("Moving appdata from '$data/cdn_mirror' to '$data/appdata'");
	$filesystem->Rename('data/cdn_mirror', 'data/appdata');
} catch (FileExistsException $exception) {
	$logger->warning("File or directory already exists at '$data/appdata'. Please move '$data/cdn_mirror' to '$data/appdata' manually if it has not been already.");
	$logger->notice('This migration will be marked as successful due to possible manual recovery.');
} catch (FileNotFoundException $exception) {
	$logger->warning("Source directory '$data/cdn_mirror' not found. Assuming that '$data/cdn_mirror' has already been moved to '$data/appdata'.");
	$logger->notice('This migration will be marked as successful due to possible manual recovery.');
} catch (FilesystemException $exception) {
	$logger->error("Unexpected filesystem error. Please move '$data/cdn_mirror' to '$data/appdata' manually.");
	throw $exception;
}

DB_UPDATE_FILE
);


//===========================================================================================
$migrations->SetVersion('40.06');
