<?php

namespace FluentFormPro\Integrations\WebHook;

if (!defined('ABSPATH')) {
    exit; // Exit if accessed directly.
}

use Exception;
use FluentForm\App\Helpers\IntegrationManagerHelper;
use FluentForm\App\Models\FormMeta;
use FluentForm\Framework\Foundation\Application;

class Client extends IntegrationManagerHelper
{
	use NotifyTrait;

	protected $app = null;
	
	protected $metaKey = 'fluentform_webhook_feed';

	public function __construct(Application $app)
	{
		$this->app = $app;

		parent::__construct(
			$this->metaKey, $app->request->get('form_id', false), true
		);
	}

	/**
	 * Get all notifications/feeds
	 * @return JSON Response
	 */
	public function getWebHooks()
	{
		$response = [
			'integrations' => $this->getAll(),
			'request_headers' => $this->getHeaders()
		];

		wp_send_json_success($response);
	}

	/**
	 * Save GetResponse Feed
	 * @return JSON Response
	 */
	public function saveWebHook()
	{
		$notification = $this->app->request->get('notification');
        $notification_id = $this->app->request->get('notification_id');
        $notification = json_decode($notification, true);

        $validated = $this->validate($notification);
        $requestUrl = sanitize_url($validated['request_url']);
        $conditionals = isset($validated['conditionals']) ? $validated['conditionals'] : [];
        $notification = fluentFormSanitizer($validated);
        $notification['request_url'] = $requestUrl;

        if (!empty($conditionals['conditions'])) {
            $notification['conditionals'] = $conditionals;
            foreach ($notification['conditionals']['conditions'] as &$condition) {
                if (isset($condition['value'])) {
                    $condition['value'] = sanitize_text_field($condition['value']);
                }
            }
        }

        if ($notification_id) {
            $notification_id = $this->resolveWebHook($notification_id)->id;
            $this->update($notification_id, $notification);
            $message = __('Feed successfully updated', 'fluentformpro');
        } else {
            $notification_id = $this->save($notification);
            $message = __('Feed successfully created', 'fluentformpro');
        }

        wp_send_json_success(array(
            'message' => $message,
            'notification_id' => $notification_id
        ), 200);
	}

	/**
	 * Delete GetResponse Feed
	 * @return JSON Response
	 */
	public function deleteWebHook()
    {
        $notification = $this->resolveWebHook($this->app->request->get('id'));

        $this->delete($notification->id);

        wp_send_json_success(array(
            'message'      => __('Selected WebHook Feed is deleted', 'fluentformpro'),
            'integrations' => $this->getAll()
        ));
    }

    protected function resolveWebHook($notificationId)
    {
        $query = FormMeta::query()
            ->where('id', absint($notificationId))
            ->where('meta_key', $this->metaKey);

        $formId = absint($this->app->request->get('form_id'));

        if ($formId) {
            $query->where('form_id', $formId);
        }

        $notification = $query->first();

        if (!$notification) {
            wp_send_json_error([
                'message' => __('Invalid webhook feed', 'fluentformpro')
            ], 422);
        }

        // Authorize the feed's STORED form. The request form_id scope above is
        // skipped when the caller omits form_id, so a delegated manager could
        // otherwise resolve, update, or delete another form's webhook feed by
        // feed id alone.
        \FluentForm\App\Modules\Acl\Acl::verify('fluentform_forms_manager', $notification->form_id);

        $notification->formattedValue = $this->getFormattedValue($notification);

        return $notification;
    }

	/**
	 * Validate inputs
	 * @param  array $notification
	 * @return array $notification
	 */
	protected function validate($notification)
	{
		$validator = fluentValidator($notification, [
            'name'                      => 'required',
            'request_body'              => 'required',
            'request_url'               => 'required|url'
        ], [
        	'name.required'              => __('Feed Name is required', 'fluentformpro'),
            'request_url.required'       => __('Request URL is required', 'fluentformpro'),
            'request_url.url'       => __('Request URL format is invalid', 'fluentformpro'),
            'request_body.required'      => __('Request body is required', 'fluentformpro')
        ])->validate();
		
		$errors = $validator->errors();

		if (!$this->validateFields($notification)) {
        	$errors['fields']['required'] = __('Field name is required', 'fluentformpro');
        }

        if (!$this->validateHeaders($notification)) {
        	$errors['headers']['required'] = __('Header name is required', 'fluentformpro');
        }
        
        $errors = apply_filters('fluentform/webhook_notification_validation_errors', $errors, $notification);
        if ($errors) {
            wp_send_json_error(array(
                'errors'  => $errors,
                'message' => __('Please fix the errors', 'fluentformpro')
            ), 400);
        }

		return $notification;
	}

	protected function validateFields($notification)
	{
		if ($notification['request_body'] != 'all_fields') {
			foreach ($notification['fields'] as $field) {
				if (empty($field['key'])) {
					return false;
				}
			}
		}
		return true;
	}

	protected function validateHeaders(&$notification)
	{
		if ($notification['with_header'] == 'yup') {
			foreach ($notification['request_headers'] as $key => &$header) {
				if (empty($header['key'])) {
					return false;
				}
			}
		}
		return true;
	}


	protected function getHeaders()
	{
		return array(
			array(
				'label' => 'Accept',
				'value' => 'Accept',
				'possible_values' => [
					'title' => 'Accept Header Samples',
                    'shortcodes' => [
                        'Accept: text/plain' => 'text/plain',
                        'Accept: text/html' => 'text/html',
                        'Accept: text/*' => 'text/*'
                    ]
				]
			),
			array(
				'label' => 'Accept-Charset',
				'value' => 'Accept-Charset',
				'possible_values' => [
					'title' => 'Accept-Charset Header Samples',
                    'shortcodes' => [
                        'Accept-Charset: utf-8' => 'utf-8',
                        'Accept-Charset: iso-8859-1' => 'iso-8859-1'
                    ]
				]
			),
			array(
				'label' => 'Accept-Encoding',
				'value' => 'Accept-Encoding',
				'possible_values' => [
					'title' => 'Accept-Encoding Header Samples',
                    'shortcodes' => [
                        'Accept-Encoding: gzip' => 'gzip',
                        'Accept-Encoding: compress' => 'compress',
                        'Accept-Encoding: deflate' => 'deflate',
                        'Accept-Encoding: br' => 'br',
                        'Accept-Encoding: identity' => 'identity',
                        'Accept-Encoding: *' => '*'
                    ]
				]
			),
			array(
				'label' => 'Accept-Language',
				'value' => 'Accept-Language',
				'possible_values' => [
					'title' => 'Accept-Language Header Samples',
                    'shortcodes' => [
                        'Accept-Language: en' => 'en',
                        'Accept-Language: en-US' => 'en-US',
                        'Accept-Language: en-GR' => 'en-GR',
                        'Accept-Language: en-US,en;q=0.5' => 'en-US,en;q=0.5'
                    ]
				]
			),
			array(
				'label' => 'Accept-Datetime',
				'value' => 'Accept-Datetime',
			),
			array(
				'label' => 'Authorization',
				'value' => 'Authorization',
			),
			array(
				'label' => 'Cache-Control',
				'value' => 'Cache-Control',
			),
			array(
				'label' => 'Connection',
				'value' => 'Connection',
			),
			array(
				'label' => 'Cookie',
				'value' => 'Cookie',
			),
			array(
				'label' => 'Content-Length',
				'value' => 'Content-Length',
			),
			array(
				'label' => 'Content-Type',
				'value' => 'Content-Type',
			),
			array(
				'label' => 'Date',
				'value' => 'Date',
			),
			array(
				'label' => 'Expect',
				'value' => 'Expect',
			),
			array(
				'label' => 'Forwarded',
				'value' => 'Forwarded',
			),
			array(
				'label' => 'From',
				'value' => 'From',
			),
			array(
				'label' => 'Host',
				'value' => 'Host',
			),
			array(
				'label' => 'If-Match',
				'value' => 'If-Match',
			),
			array(
				'label' => 'If-Modified-Since',
				'value' => 'If-Modified-Since',
			),
			array(
				'label' => 'If-None-Match',
				'value' => 'If-None-Match',
			),
			array(
				'label' => 'If-Range',
				'value' => 'If-Range',
			),
			array(
				'label' => 'If-Unmodified-Since',
				'value' => 'If-Unmodified-Since',
			),
			array(
				'label' => 'Max-Forwards',
				'value' => 'Max-Forwards',
			),
			array(
				'label' => 'Origin',
				'value' => 'Origin',
			),
			array(
				'label' => 'Pragma',
				'value' => 'Pragma',
			),
			array(
				'label' => 'Proxy-Authorization',
				'value' => 'Proxy-Authorization',
			),
			array(
				'label' => 'Range',
				'value' => 'Range',
			),
			array(
				'label' => 'Referer',
				'value' => 'Referer',
			),
			array(
				'label' => 'TE',
				'value' => 'TE',
			),
			array(
				'label' => 'User-Agent',
				'value' => 'User-Agent',
			),
			array(
				'label' => 'Upgrade',
				'value' => 'Upgrade',
			),
			array(
				'label' => 'Via',
				'value' => 'Via',
			),
			array(
				'label' => 'Warning',
				'value' => 'Warning',
			),
		);
	}
}
