<?php

namespace Blocksy;

class DynamicCss {
	private $wp_filesystem = null;

	public function __construct() {
		add_filter(
			'blocksy:dynamic-css:has_files_cache',
			function ($r) {
				if (is_customize_preview()) {
					if (! wp_doing_ajax()) {
						return false;
					}
				}

				if (! $this->should_use_files()) {
					return false;
				}

				$theme_paths = $this->maybe_prepare_theme_uploads_path();

				if (! $theme_paths) {
					return false;
				}

				foreach ($this->get_chunks() as $chunk) {
					if (! $chunk['enabled']) {
						continue;
					}

					$file = $theme_paths['css_path'] . '/' . $chunk['filename'];

					if (! file_exists($file)) {
						return false;
					}
				}

				return true;
			}
		);

		add_filter(
			'blocksy_performance_end_customizer_options',
			function ($opts) {
				$opts['dynamic_css_file'] = [
					'label' => __( 'Dynamic CSS Output', 'blocksy-companion' ),
					'type' => 'ct-radio',
					'value' => 'file',
					'view' => 'text',
					'desc' => __( 'The strategy of outputting the dynamic CSS. File - all the CSS code will be placed in a static file, otherwise it will be placed inline in head.', 'blocksy-companion' ),
					'choices' => [
						'file' => __( 'File', 'blocksy-companion' ),
						'inline' => __( 'Inline', 'blocksy-companion' ),
					],
				];

				$opts[blocksy_rand_md5()] = [
					'type' => 'ct-divider',
				];

				return $opts;
			}
		);

		add_action('current_screen', function () {
			$screen = get_current_screen();

			if ($screen->base === 'plugins') {
				if (
					// phpcs:ignore WordPress.Security.NonceVerification.Recommended
					isset($_GET['activate-multi'])
					||
					// phpcs:ignore WordPress.Security.NonceVerification.Recommended
					isset($_GET['activate'])
					||
					// phpcs:ignore WordPress.Security.NonceVerification.Recommended
					isset($_GET['deactivate'])
					||
					// phpcs:ignore WordPress.Security.NonceVerification.Recommended
					isset($_GET['deactivate-multi'])
				) {
					$this->generate_css_files();
				}
			}
		});

		add_action('blocksy:dynamic-css:refresh-caches', function () {
			$this->generate_css_files();
		});

		add_action('init', function () {
			$this->enqueue_dynamic_css();
		});

		// Needs to run very early.
		// Will catch when the import is done and will refresh the dynamic CSS.
		// All in One WP Migration compatibility.
		add_action('ai1wm_status_import_done', function () {
			do_action('blocksy:dynamic-css:refresh-caches');
		});
	}

	public function should_use_files() {
		return blc_theme_functions()->blocksy_get_theme_mod('dynamic_css_file', 'file') === 'file';
	}

	public function get_chunks() {
		return [
			[
				'filename' => 'global.css',
				'context' => 'files:global',
				'enabled' => true
			],
		];
	}

	public function enqueue_dynamic_css() {
		if (
			is_admin()
			||
			is_login()
		) {
			return;
		}

		if (! blc_theme_functions()->blocksy_has_dynamic_css_in_frontend()) {
			return;
		}

		if (
			! function_exists('blocksy_has_css_in_files')
			||
			! blocksy_has_css_in_files()
		) {
			return;
		}

		$theme_paths = $this->maybe_prepare_theme_uploads_path();

		if (! $theme_paths) {
			return;
		}

		foreach ($this->get_chunks() as $chunk) {
			if (! $chunk['enabled']) {
				continue;
			}

			$file = $theme_paths['css_path'] . '/' . $chunk['filename'];
			$url = $theme_paths['css_url'] . '/' . $chunk['filename'];

			wp_enqueue_style(
				'blocksy-dynamic-' . pathinfo($chunk['filename'], PATHINFO_FILENAME),
				set_url_scheme($url),
				[],
				substr((string) filemtime($file), -5, 5)
			);
		}
	}

	public function generate_css_files() {
		if (! $this->should_use_files()) {
			return false;
		}

		$theme_paths = $this->maybe_prepare_theme_uploads_path([
			'should_generate' => true
		]);

		if (! $theme_paths) {
			return false;
		}

		$chunks = $this->get_chunks();

		foreach ($chunks as $chunk) {
			if (! $chunk['enabled']) {
				continue;
			}

			$file = $theme_paths['css_path'] . '/' . $chunk['filename'];

			if (
				function_exists('blocksy_get_dynamic_css_file_content')
				&&
				$this->wp_filesystem
			) {
				$this->wp_filesystem->put_contents(
					$file,
					blocksy_get_dynamic_css_file_content(['context' => $chunk['context']])
				);
			}
		}
	}

	public function maybe_prepare_theme_uploads_path($args = []) {
		$args = wp_parse_args($args, [
			'should_generate' => false,
		]);

		require_once (ABSPATH . '/wp-admin/includes/file.php');
		WP_Filesystem();

		global $wp_filesystem;

		$this->wp_filesystem = $wp_filesystem;
		$uploads = wp_upload_dir();

		// Theme folders in `uploads` directory.
		$folders_in_uploads = array(
			'base'  => 'blocksy',
			'css'   => 'blocksy/css'
		);

		$theme_paths = [];

		foreach($folders_in_uploads as $folder => $path) {
			// Server path.
			$theme_paths[
				$folder . '_path'
			] = $uploads['basedir'] . '/' . $path;

			// URL.
			$theme_paths[
				$folder . '_url'
			] = $uploads['baseurl'] . '/' . $path;
		}

		// Custom css file.

		if (! $this->has_direct_access($theme_paths['css_path'])) {
			return false;
		}

		if (null === $this->wp_filesystem) {
			return false;
		}

		if ($args['should_generate']) {
			foreach(array_keys($folders_in_uploads) as $folder) {
				$path = $theme_paths[$folder . '_path'];
				$parent = dirname($path);

				if ($this->wp_filesystem->is_writable($parent)) {
					if (! $this->wp_filesystem->is_dir($path)) {
						$this->wp_filesystem->mkdir($path);
					}
				}
			}
		}

		return $theme_paths;
	}

	public function has_direct_access($context = null) {
		require_once ABSPATH . 'wp-admin/includes/file.php';
		WP_Filesystem();

		/** @var WP_Filesystem_Base $wp_filesystem */
		global $wp_filesystem;

		if ($wp_filesystem) {
			if ($wp_filesystem->method !== 'direct') {
				return false;
			} else {
				return true;
			}
		}

		if (get_filesystem_method([], $context) === 'direct') {
			ob_start();

			$creds = request_filesystem_credentials(
				admin_url(),
				'',
				false,
				$context,
				null
			);

			ob_end_clean();

			if (WP_Filesystem($creds)) {
				return true;
			}
		}

		return false;
	}

	public function get_wp_filesystem() {
		return $this->wp_filesystem;
	}
}

