<?php
namespace SabaiApps\Directories\Component\Faker\Generator;

use SabaiApps\Directories\Component\Field\IField;
use SabaiApps\Directories\Component\Form\Form;
use SabaiApps\Directories\Exception;
use SabaiApps\Directories\Component\Entity\Type\IEntity;

class GeneratedPhotosPhotoGenerator extends AbstractGenerator {

	protected function _fakerGeneratorInfo() {
		return array(
			'label'            => __( 'Generated Photos Photo Generator', 'directories-pro' ),
			'description'      => __( 'Generate user face photos using Generated Photos API (https://generated.photos/).', 'directories-pro' ),
			'field_types'      => array( 'wp_image' ),
			'add_probability'  => true,
			'default_settings' => array(
				'max' => 5,
			),
		);
	}

	public function fakerGeneratorSettingsForm( IField $field, array $settings, $mode, array $parents = array() ) {
		$form = array(
			'api_key' => array(
				'#type'                  => 'textfield',
				'#title'                 => __( 'Generated Photos API key', 'directories-pro' ),
				'#description'           => sprintf(
					$this->_application->H( __( 'Get API key from %s.', 'directories-pro' ) ),
					'<a href="https://generated.photos/api" target="_blank" rel="nofollow">https://generated.photos/api</a>'
				),
				'#description_no_escape' => true,
				'#required'              => function ( $form ) use ( $parents ) {
					return $form->getValue( array_merge( array_slice( $parents, 0, -2 ), array( 'generator' ) ) ) === 'generated_photos';
				},
				'#default_value'         => ( $api_key = $this->_application->getPlatform()->getCache( 'faker_generated_photos_api_key' ) ) ? $api_key : null,
				'#element_validate'      => array(
					function ( Form $form, &$value ) {
						if ( empty( $value ) ) {
							return;
						}
						$this->_application->getPlatform()->setCache( $value, 'faker_generated_photos_api_key', 86400 * 365 );
					},
				),
			),
			'gender'  => array(
				'#type'          => 'select',
				'#title'         => __( 'Gender', 'directories-pro' ),
				'#options'       => array(
					''       => __( 'Any', 'directories-pro' ),
					'male'   => __( 'Male', 'directories-pro' ),
					'female' => __( 'Female', 'directories-pro' ),
				),
				'#default_value' => '',
			),
			'max'     => $this->_getMaxNumItemsSettingForm( $field, $settings['max'] ),
		);
		if ( $mode !== 'new' ) {
			$form['preserve_existing'] = array(
				'#type'          => 'checkbox',
				'#title'         => __( 'Preserve existing', 'directories-pro' ),
				'#description'   => __( 'If checked, existing photos will be preserved and new photos will be added to them.', 'directories-pro' ),
				'#default_value' => true,
			);
		}
		return $form;
	}

	public function fakerGeneratorGenerate( IField $field, array $settings, array &$formStorage, ?IEntity $entity = null ) {
		if ( empty( $settings['api_key'] ) ) {
			return;
		}

		if ( ! $user_photos = $this->_application->getPlatform()->getCache( 'faker_generated_photos_photos' ) ) {
			$url    = 'https://api.generated.photos/api/v1/faces';
			$params = array( 'perpage' => 50 );
			if ( ! empty( $settings['gender'] ) ) {
				$params['gender'] = $settings['gender'];
			}
			try {
				$result = $this->_application->getPlatform()->remoteGet(
					$this->_application->Url( $url, $params, '', '&' ),
					array(
						'headers' => array(
							'Authorization' => 'API-Key ' . $settings['api_key'],
							'Accept'        => 'application/json',
							'Cache-Control' => 'no-cache',
						),
					)
				);

				if ( ( ! $user_photos = json_decode( $result, true ) )
					|| empty( $user_photos['faces'] )
				) {
					throw new Exception\RuntimeException( 'Failed decoding JSON returned from generated.photos.' );
				}
				$user_photos = $user_photos['faces'];
			} catch ( \Exception $e ) {
				$this->_application->logError( $e->getMessage() );
				return false;
			}
			$this->_application->getPlatform()->setCache( $user_photos, 'faker_generated_photos_photos', 86400 );
		}

		if ( empty( $user_photos ) ) {
			return false;
		}

		if ( ! isset( $formStorage['faker_generated_photos_photos'] ) ) {
			$formStorage['faker_generated_photos_photos'] = array();
		}

		$ret = array();
		$num = $this->_getMaxNumItems( $field, $settings['max'] );
		$i   = 0;
		do {
			++$i;
			$index = mt_rand( 0, count( $user_photos ) - 1 );
			$photo = $user_photos[ $index ];
			unset( $user_photos[ $index ] );
			$user_photos = array_values( $user_photos );

			if ( isset( $ret[ $photo['id'] ] ) ) {
				continue;
			}

			if ( ! isset( $formStorage['faker_generated_photos_photos'][ $photo['id'] ] ) ) {
				$url = isset( $photo['urls'][5]['1024'] ) ? $photo['urls'][5]['1024'] : $photo['urls'][4]['512'];
				try {
					$file_path = $this->_application->getPlatform()->downloadUrl( $url );
				} catch ( \Exception $e ) {
					$this->_application->logError( $e );
					continue;
				}

				try {
					$file = $this->_application->getPlatform()->uploadFile(
						$file_path,
						'generated-photos-photo-' . $photo['id'] . '.jpeg',
						$photo['id']
					);
				} catch ( \Exception $e ) {
					@unlink( $file_path );
					$this->_application->logError( $e );
					continue;
				}

				$formStorage['faker_generated_photos_photos'][ $photo['id'] ] = $file;
			}

			$ret[ $photo['id'] ] = $formStorage['faker_generated_photos_photos'][ $photo['id'] ];

		} while ( count( $ret ) < $num && $i < $num + 5 && count( $user_photos ) > 0 );

		$this->_application->getPlatform()->setCache( $user_photos, 'faker_generated_photos_photos', 86400 * 7 );

		$ret = array_values( $ret );

		if ( isset( $entity )
			&& ! empty( $settings['preserve_existing'] )
			&& ( $current_photos = $entity->getFieldValue( $field->getFieldName() ) )
		) {
			foreach ( $current_photos as $photo ) {
				$ret[] = $photo;
			}
		}

		return $ret;
	}
}
