<?php

namespace GravityKit\GravityExport\Addon;

use GFExcel\Addon\AddonInterface;
use GFExcel\Addon\AddonTrait;
use Gravity_Forms\Gravity_Forms\Settings\Fields\Base;
use GravityKit\GravityExport\Exporting\CustomExportEndpoint;
use GravityKit\GravityExport\Exporting\ExportAsHtml;
use GravityKit\GravityExport\Foundation\Logger\Framework as Logger;
use GravityKit\GravityExport\Exporting\RemoveEmptyColumns;
use GravityKit\GravityExport\Foundation\Settings\Framework as Foundation;
use GravityKitFoudation;

class GravityExportAddon extends \GFAddOn implements AddonInterface {
	use AddonTrait;

	public const SETTINGS_PLUGIN_ID = 'gravityexport';

	/**
	 * @inheritdoc
	 * @since 1.0
	 */
	protected $_min_gravityforms_version = '2.0';

	/**
	 * @inheritDoc
	 * @since 1.0
	 */
	protected $_capabilities_form_settings = 'gravityforms_export_entries';

	/**
	 * @inheritdoc
	 * @since 1.0
	 */
	protected $_capabilities_settings_page = 'gravityforms_export_entries';

	/**
	 * {@inheritdoc}
	 */
	protected $_path = 'gravityexport/gravityexport.php';

	/**
	 * @inheritdoc
	 * @since 1.0
	 */
	protected $_full_path = __FILE__;

	/**
	 * @inheritdoc
	 * @since 1.0
	 */
	protected $_url = 'https://gfexcel.com';

	/**
	 * @inheritdoc
	 * @since 1.0
	 */
	protected $_title = GK_GRAVITYEXPORT_PLUGIN_NAME;

	/**
	 * @inheritdoc
	 * @since 1.0
	 */
	protected $_short_title = GK_GRAVITYEXPORT_PLUGIN_NAME;

	/**
	 * @inheritdoc
	 * @since 1.0
	 */
	protected $_version = GK_GRAVITYEXPORT_PLUGIN_VERSION;

	/**
	 * @inheritdoc
	 * @since 1.0
	 */
	protected $_slug = GK_GRAVITYEXPORT_PLUGIN_SLUG;

	/**
	 * The foundation settings instance.
	 * @since $ver$
	 * @var Foundation
	 */
	protected $foundation;

    /**
	 * @inheritdoc
	 * @since 1.0
	 */
	public function minimum_requirements(): array {
		return [
			'php' => [
				'version'    => '7.3',
				'extensions' => [
					'openssl',
					'json',
				],
			]
		];
	}

	/**
	 * Creates the instance.
	 * @since $ver$
	 */
	public function __construct() {
		$this->foundation = Foundation::get_instance();
		add_filter( 'gk/foundation/initialized', function () {
			if ( class_exists( GravityKitFoudation::class ) ) {
				$this->foundation = GravityKitFoundation::settings();
			}
		} );

		parent::__construct();
    }

	/**
	 * Instance of the Foundation logger class.
	 * @since 1.1.3
	 * @var Logger
	 */
	public $logger;

	/**
	 * Returns the logger instance for this plugin.
	 * @since 1.1.3
	 * @return Logger
	 */
	final public static function getLogger(): Logger {
		$self = self::get_instance();

		if ( ! isset( $self->logger ) ) {
			$self->logger = Logger::get_instance( self::SETTINGS_PLUGIN_ID, GK_GRAVITYEXPORT_PLUGIN_NAME );
		}

		return $self->logger;
	}

	/**
	 * Try foundation settings as backup.
	 *
	 * @since $ver$
	 * @inerhitDoc
	 */
	public function get_plugin_setting( $setting_name ) {
		return
			parent::get_plugin_setting( $setting_name )
			?? $this->foundation->get_plugin_setting( self::SETTINGS_PLUGIN_ID, $setting_name );
	}

	/**
	 * Merge foundation settings onto the plugin settings.
	 *
	 * @since $ver$
	 * @inerhitDoc
	 */
	public function get_plugin_settings() {
		return array_merge(
			$this->foundation->get_plugin_settings( self::SETTINGS_PLUGIN_ID ),
			parent::get_plugin_settings() ?: []
		);
	}

	/**
	 * @inheritdoc
	 * @since 1.0
	 */
	public function render_uninstall() {
		return null;
	}

    /**
	 * @inheritDoc
	 * @since 1.1
	 */
	public function init() {
		parent::init();
		add_filter( 'gk/foundation/settings/data/plugins', \Closure::fromCallable( [ $this, 'add_sections' ] ) );

		// Start features.
		new RemoveEmptyColumns( $this );
		new ExportAsHtml( $this );
	}

    /**
     * @inheritDoc
     * @since 1.5.0
     */
    public function pre_init(): void
    {
        parent::pre_init();

        // Needs to register before the `init` event to register the custom endpoint in time.
        new CustomExportEndpoint( $this );
    }

	/**
	 * Adds GravityExport settings to Foundation.
	 *
	 * @since 1.1
	 *
	 * @param array $plugin_data Plugins data.
	 *
	 * @return array Plugins data.
	 */
	private function add_sections( array $plugin_data ): array {
		$sections = $this->remove_empty_sections( apply_filters( 'gk/gravityexport/settings/sections', [
			[
				'title'    => esc_html__( 'General settings', 'gk-gravityexport' ),
				'id'       => 'general-section',
				'settings' => [],
			],
		], $this ) );

		if ( ! $sections ) {
			return $plugin_data;
		}

		$plugin_data[] = [
			'id'       => self::SETTINGS_PLUGIN_ID,
			'title'    => 'GravityExport',
			'icon'     => "data:image/svg+xml,%3Csvg width='250' height='250' viewBox='0 0 250 250' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='250' height='250' rx='60' fill='%23653EFF'/%3E%3Cg clip-path='url(%23clip0_104_4215)'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M164.311 152.629C163.389 153.551 162.065 153.551 160.973 152.63L157.636 149.293C156.714 148.371 156.714 146.877 157.636 145.955L173.87 129.72H144.868C142.518 150.958 124.528 167.481 102.665 167.481C79.204 167.481 60.1851 148.462 60.1851 125C60.1851 101.538 79.204 82.5189 102.665 82.5189C120.237 82.5189 135.27 93.2096 141.725 108.427C142.236 109.574 141.32 110.839 140.075 110.839H134.254C133.148 110.839 132.164 110.205 131.636 109.234C126.047 98.9524 115.193 91.9592 102.665 91.9592C84.4174 91.9592 69.6249 106.752 69.6249 125C69.6249 143.248 84.4174 158.041 102.665 158.041C119.305 158.041 133.034 145.726 135.366 129.72H100.305C99.0014 129.72 97.9448 128.663 97.9448 127.36V122.64C97.9448 121.336 99.0014 120.28 100.305 120.28H173.871L157.636 104.045C156.714 103.123 156.714 101.629 157.636 100.707L160.973 97.3702C162.067 96.4486 163.389 96.4486 164.311 97.3702L188.602 121.71C190.445 123.505 190.445 126.494 188.602 128.337L164.311 152.629Z' fill='white'/%3E%3C/g%3E%3Cdefs%3E%3CclipPath id='clip0_104_4215'%3E%3Crect width='130' height='84.9622' fill='white' transform='translate(60 82.5189)'/%3E%3C/clipPath%3E%3C/defs%3E%3C/svg%3E%0A",
			'sections' => $sections,
			'assets'   => [
				'scripts' => [
					[
						'file' => plugin_dir_path( GK_GRAVITYEXPORT_PLUGIN_FILE ) . 'assets/js/gravityexport-settings.js',
					],
				],
				'styles'  => [
					[
						'file' => plugin_dir_path( GK_GRAVITYEXPORT_PLUGIN_FILE ) . 'assets/css/gravityexport-settings.css',
					],
				],
			],
		];

		return $plugin_data;
	}

	/**
	 * Update a single setting.
	 *
	 * @since 1.0
	 *
	 * @param string $key   The key to store.
	 * @param mixed  $value The value to store for the key
	 *
	 * @return boolean Whether the settings were updated or not
	 */
	public function update_plugin_setting( $key, $value ): bool {
		if ( ! is_string( $key ) ) {
			return false;
		}

		$settings         = parent::get_plugin_settings();
		$existing_setting = $settings[ $key ] ?? false;

		if ( $existing_setting === $value ) {
			return false;
		}

		$settings[ $key ] = $value;

		parent::update_plugin_settings( $settings );

		return true;
	}

	/**
	 * @inheritDoc
	 * @since 1.0
	 */
	public function update_plugin_settings( $settings ) {
		// keep settings that have not been changed.
		$plugin_settings = parent::get_plugin_settings();
		$settings        = array_merge( $plugin_settings, $settings );

		parent::update_plugin_settings( $settings );
	}

	/***
	 * Render the save button for settings pages.
	 *
	 * Same as GFAddOn::settings_save(), but allows for overriding the button class.
	 *
	 * @since 1.0
	 * @inheritDoc
	 *
	 * @return string
	 */
	public function settings_save( $field, $echo = true ): string {
		$button = parent::settings_save( $field, false );

		// Replace the class
		if ( ! empty( $field['class'] ) ) {
			$button = str_replace( 'button-primary gfbutton', esc_attr( $field['class'] ), $button );
		}

		$button .= wp_nonce_field( GK_GRAVITYEXPORT_PLUGIN_SLUG, '_wpnonce', true, false );

		if ( $echo ) {
			echo $button;
		}

		return $button;
	}

	/***
	 * Render the save button for settings pages.
	 *
	 * @since 1.0
	 *
	 * @param bool  $echo  True to echo the output to the screen; false to simply return the contents as a string.
	 *
	 * @param array $field Field array containing the configuration options of this field.
	 *
	 * @return string The HTML
	 */
	public function settings_submit( $field, $echo = true ): string {
		$field['type'] = ( isset( $field['type'] ) && in_array( $field['type'], [
				'submit',
				'reset',
				'button',
			] ) ) ? $field['type'] : 'submit';

		$attributes = $this->get_field_attributes( $field );
		$value      = rgar( $field, 'value' ) ? rgar( $field, 'value' ) : rgar( $field, 'default_value' );
		// TODO: Should the value from a button be set from a setting?
		// $value         = $this->get_setting( $field['name'], $default_value );

		$attributes['class'] = isset( $field['class'] ) ? esc_attr( $field['class'] ) : $attributes['class'];

		$html       = $field['html_before'] ?? '';
		$html_after = $field['html_after'] ?? '';

		if ( ! rgar( $field, 'value' ) ) {
			$field['value'] = esc_html__( 'Update Settings', 'gk-gravityexport' );
		}

		$attributes = $this->get_field_attributes( $field );

		unset( $attributes['html_before'], $attributes['html_after'], $attributes['tooltip'] );

		if ( $field instanceof Base ) {
			$html .= $field->get_description();
		}

		if ( $field['tag'] ?? 'input' === 'button' ) {
			$html .= '<button
                    type="' . esc_attr( $field['type'] ) . '"
                    name="' . esc_attr( $field['name'] ) . '"
		            value="' . esc_attr( $value ) . '" ' .
			         implode( ' ', $attributes ) .
			         ' >' . $field['button_text'] ?? esc_attr( $value ) . '</button>';
		} else {
			$html .= '<input
                    type="' . esc_attr( $field['type'] ) . '"
                    name="' . esc_attr( $field['name'] ) . '"
                    value="' . esc_attr( $value ) . '" ' .
			         implode( ' ', $attributes ) .
			         ' />';
		}

		$html .= $html_after;
		$html .= wp_nonce_field( GK_GRAVITYEXPORT_PLUGIN_SLUG, '_wpnonce', true, false );

		if ( $echo ) {
			echo $html;
		}

		return $html;
	}

	/**
	 * Return the plugin's icon for the plugin/form settings menu.
	 *
	 * @since 1.0
	 *
	 * @return string
	 */
	public function get_menu_icon(): string {
		return '<svg style="height: 24px;" enable-background="new 0 0 226 148" height="148" viewBox="0 0 226 148" width="226" xmlns="http://www.w3.org/2000/svg"><path d="m176.8 118.8c-1.6 1.6-4.1 1.6-5.7 0l-5.7-5.7c-1.6-1.6-1.6-4.1 0-5.7l27.6-27.4h-49.2c-4.3 39.6-40 68.2-79.6 63.9s-68.2-40-63.9-79.6 40.1-68.2 79.7-63.9c25.9 2.8 48.3 19.5 58.5 43.5.6 1.5-.1 3.3-1.7 3.9-.4.1-.7.2-1.1.2h-9.9c-1.9 0-3.6-1.1-4.4-2.7-14.7-27.1-48.7-37.1-75.8-22.4s-37.2 48.8-22.4 75.9 48.8 37.2 75.9 22.4c15.5-8.4 26.1-23.7 28.6-41.2h-59.4c-2.2 0-4-1.8-4-4v-8c0-2.2 1.8-4 4-4h124.7l-27.5-27.5c-1.6-1.6-1.6-4.1 0-5.7l5.7-5.7c1.6-1.6 4.1-1.6 5.7 0l41.1 41.2c3.1 3.1 3.1 8.2 0 11.3z"/></svg>';
	}

	/**
	 * Uninstall extension.
	 *
	 * @since 1.0
	 *
	 * @return bool
	 */
	public function uninstall(): bool {
		/**
		 * Set the path so that Gravity Forms can de-activate the plugin.
		 *
		 * @see  \GFAddOn::uninstall_addon
		 * @uses deactivate_plugins()
		 */
		$this->_path = GK_GRAVITYEXPORT_PLUGIN_FILE;

		return true;
	}

	/**
	 * Returns only sections with settings.
	 * @since $ver$
	 *
	 * @param array $sections The sections.
	 *
	 * @return array The filtered sections.
	 */
	private function remove_empty_sections( array $sections ): array {
		$sections = array_filter( $sections, function ( array $section ) {
			return ! empty( $section['settings'] ?? [] );
		} );

		return array_values( $sections );
	}
}
