<?php

namespace Themeco\Cornerstone\Elements;

/**
 * Access to Cornerstone data
 */
class Migrations {

	public function migrate( $elements, $direct = false ) {

		if ( !is_array( $elements ) ) {
			return $elements;
		}


		foreach ($elements as $key => $element) {
			$is_classic = ! isset( $element['_type'] ) || ('section' === $element['_type'] && isset( $element['elements'] ) );

			$elements[$key] = $this->migrate_element( $is_classic ? $this->migrate_classic_element( $element ) : $element, $direct );
		}

		return $elements;
	}

	/**
	 * This will migrate an elements base values.
	 * We do not have logic at this time to migrate include values so include values should not change between versions
	 */
	public function apply_base_migrations( $element, $base_migrations, $base_values ) {

		if ( ! isset( $element['_m'] ) ) {
			$element['_m'] = [];
		}

		if ( ! isset( $element['_m']['e'] ) ) {
			$element['_m']['e'] = 0;
		}

		$start = $element['_m']['e'];
		$latest = count($base_migrations);

		if ($latest > $start) {
			$element['_m']['e'] = $latest;

			foreach ($base_migrations as $index => $migration ) {
				if ($index < $start) continue;

				// Explicitly set unset values to the earliest possible value in the migration list
				foreach($migration as $key => $value) {
					if ( ! isset( $element[$key] ) ) {
						$element[$key] = $value;
					}
				}

				// Unset values identicial to the the new default
				foreach($migration as $key => $value) {
					if ( isset( $element[$key] ) && $element[$key] === $base_values[$key] ) {
						unset( $element[$key] );
					}
				}
			}
		}

		return $element;

	}

	public function migrate_element( $element, $direct = false ) {

		// Invalid element passed from prior version
		if ( is_string($element)) {
			throw new \DomainException("Invalid Element passed " . $element);
		}

		$element = apply_filters("cs_element_before_migrate", $element);

		$def = cs_get_element( $element['_type'] );
		$base_values = $def->get_aggregated_values();
		$element = $this->query_style_migrations( $element, $base_values );

		$base_migrations = $def->get_migrations();
		if ( count( $base_migrations ) > 0 ) {
			$element = $this->apply_base_migrations( $element, $base_migrations, $base_values );
		}

		if ( !$direct && isset( $element['_modules'] ) ) {
			foreach ( $element['_modules'] as $index => $child ) {
				// Child is set to string that we can't reference
				// like it will be e4, but we can't know what e4 is
				// @TODO why are some of these old blocks broken?
				if (is_string($child)) {
					unset($element['_modules'][$index]);
					continue;
				}

				$element['_modules'][$index] = $this->migrate_element( $child );
			}
		}

		return $element;
	}

	public function migrate_classic_element( $element ) {

		// Ensure '_type' is set
		if ( isset( $element['elType'] ) ) {
			$element['_type'] = $element['elType'];
			unset($element['elType']);
		}

		if ( !isset( $element['_type'] ) ) {
			return [ '_type' => 'unknown' ];
		}

		if ( false === strpos($element['_type'], 'classic:' ) ) {
			$element['_type'] = 'classic:' . $element['_type'];
		}

		if ( isset( $element['title'] ) && ! isset( $element['_label'] ) ) {
			$element['_label'] = $element['title'];
			unset( $element['title'] );
		}

		// Assign '_type' per element for children, and remove parent 'childType'
		if ( isset( $element['childType'] ) ) {
			if ( $element['childType'] != 'any' && isset( $element['elements'] ) ) {
				foreach ( $element['elements'] as $index => $child ) {
					$element['elements'][$index]['_type'] = $element['childType'];
				}
			}
			unset( $element['childType'] );
		}

		// Some quick inline layout migrations instead of checking the version for every individual element
		if ( 'classic:row' == $element['_type'] && isset( $element['columnLayout'] ) ) {
			unset($element['columnLayout']);
		}

		if ( 'classic:column' == $element['_type'] && isset( $element['active'] ) ) {
			$element['_active'] = $element['active'];
			unset($element['active']);
		}

		if ( isset( $element['custom_id'] ) ) {
			$element['id'] = $element['custom_id'];
			unset($element['custom_id']);
		}

		if ( isset( $element['border'] ) ) {
			if ( !isset( $element['border_width'] ) ) {
				$element['border_width'] = $element['border'];
			}
			unset( $element['border'] );
		}

		// Remap old visibility
		if ( isset( $element['visibility'] ) && is_array( $element['visibility'] ) ) {
			foreach ( $element['visibility'] as $key => $value) {
				$element['visibility'][$key] = str_replace( 'x-hide-', '', $value );
			}
		}

		// Remap old text align
		if ( isset( $element['text_align'] ) ) {
			$ta_migrate = array( 'left-text' => 'l', 'center-text' => 'c', 'right-text' => 'r', 'justify-text' => 'j' );
			if ( isset( $ta_migrate[ $element['text_align'] ] ) ) {
				$element['text_align'] = $ta_migrate[ $element['text_align'] ];
			}
		}

		if ( isset( $element['elements'] ) ) {
      $element['_modules'] = array();
			foreach ( $element['elements'] as $index => $child ) {
				$element['_modules'][$index] = $this->migrate_classic_element( $child );
			}
      unset($element['elements']);
		}

		return $element;

	}

	public function migrateFontWeight( $input ) {
		return cornerstone('GlobalFonts')->migrateLegacyFontWeight( $input );
	}

	public function migrateFontFamily( $input ) {
		return cornerstone('GlobalFonts')->migrateLegacyFontFamily( $input );
	}

	public function migrateFonts( $element ) {

		$bp_key = null;
		if ( isset( $element['_bp_base'] ) ) {
			$maybe_key = '_bp_data' . $element['_bp_base'];
			if ( isset( $element[$maybe_key] ) ) {
				$bp_key = $maybe_key;
			}
		}

		$def = cs_get_element( $element['_type'] );

		$fwKeys = $def->get_designated_keys('style:font-weight');;
		$ffKeys = $def->get_designated_keys('style:font-family');;

		foreach($fwKeys as $key) {
			if ( isset( $element[$key] ) ) {
				$element[$key] = $this->migrateFontWeight( $element[$key] );
			}
			if ( isset( $element[$bp_key][$key])) {
				$element[$bp_key][$key] = array_map( [ $this, 'migrateFontWeight'], $element[$bp_key][$key]);
			}
		}

		foreach($ffKeys as $key) {
			if ( isset( $element[$key] ) ) {
				$element[$key] = $this->migrateFontFamily( $element[$key] );
			}
			if ( isset( $element[$bp_key][$key])) {
				$element[$bp_key][$key] = array_map( [ $this, 'migrateFontFamily'], $element[$bp_key][$key]);
			}
		}

		return $element;
	}

	public function query_style_migrations( $element, $base_values ) {

		// All elements prior Cornerstone 6 do not have a base breakpoints
		if ( ! isset( $element['_bp_base'] ) ) {
			// treat legacy content as "desktop first" with 5 breakpoints (legacy stacks)
			$element['_bp_base'] = '4_4';
			// Will return an element that is "desktop first"
			$element = $this->layout_element_responsive_migration( $element );
		}

		list($base, $ranges, $size) = cornerstone('Breakpoints')->breakpointConfig();

		if ($base . '_' . $size !== $element['_bp_base'] ) { // current element does not match current base breakpoint
			$breakpointData = cornerstone()->resolve(BreakpointData::class);
			$breakpointData->setElement($element, $base_values);
			$element = $breakpointData->convertTo($base, $size);
		}

		return $this->migrateFonts( $element );

	}

	public function layout_element_responsive_migration( $element ) {

		// Only migrate elements with legacy responsive values

		if ( ! in_array( $element['_type'], ['layout-grid', 'layout-cell', 'layout-row' ], true ) ) {
			return $element;
		}

		if ( $element['_type'] === 'layout-grid') {

			// migrate md,lg, and xl values from their previous defaults to ensure they exist

			if ( ! isset( $element['layout_grid_template_columns_md'] ) ) {
				$element['layout_grid_template_columns_md'] = '1fr 1fr';
			}

			if ( ! isset( $element['layout_grid_template_columns_lg'] ) ) {
				$element['layout_grid_template_columns_lg'] = '1fr 1fr';
			}

			if ( ! isset( $element['layout_grid_template_columns_xl'] ) ) {
				$element['layout_grid_template_columns_xl'] = '1fr 1fr 1fr 1fr';
			}

			return $this->migrate_layout_query_values( $element, [
				'layout_grid_template_columns' => '1fr',
				'layout_grid_template_rows'    => 'auto',
			]);
		}

		if ( $element['_type'] === 'layout-row') {
			return $this->migrate_layout_query_values( $element, [ 'layout_row_layout' => '100%' ] );
		}

		if ( $element['_type'] === 'layout-cell') {
			return $this->migrate_layout_query_values( $element, [
				'layout_cell_column_start'  => '',
				'layout_cell_column_end'    => '',
				'layout_cell_row_start'     => '',
				'layout_cell_row_end'       => '',
				'layout_cell_justify_self'  => 'auto',
				'layout_cell_align_self'    => 'auto'
			] );
		}



		return $element;

	}

	public function migrate_layout_query_values( $element, $values) {
		foreach ($values as $key => $default) {
			$element = $this->migrate_layout_query_value($element, $key, $default);
		}

		return $element;
	}

	public function migrate_layout_query_value( $element, $dataKey, $default ) {

		$breakpointKey = '_bp_data' . $element['_bp_base'];
		$allValues = [];

		$bps = ['xl', 'lg', 'md', 'sm', 'xs'];

		// Create an ordered list with all values present
		foreach ($bps as $index => $bp) {
			$bp_key = $dataKey . '_' . $bp;
			$allValues[$index] = isset($element[$bp_key]) ? $element[$bp_key] : $default;
		}

		// Set the new base key if it doesn't match the element default
		if ($allValues[0] !== $default) {
			$element[$dataKey] = $allValues[0];
		}


		// populate query values
		$queryValues = [];
		$previous = $allValues[0];
		$hasQueryValues = false;

		foreach ($allValues as $index => $value) {
			if ($index === 0 || $value === $previous) {
				$queryValues[$index] = null;
				continue;
			}
			$previous = $value;
			$queryValues[$index] = $value;
			$hasQueryValues = true;
		}

		// set the query values
		if ($hasQueryValues) {
			if ( ! isset( $element[$breakpointKey] ) ) {
				$element[$breakpointKey] = [];
			}
			$element[$breakpointKey][$dataKey] = array_reverse($queryValues);

		}

		return $element;
	}

}
