<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}
if ( ! class_exists( 'BWF_CO' ) ) {
	#[AllowDynamicProperties]
	abstract class BWF_CO {

		public static $GET = 1;
		public static $POST = 2;
		public static $DELETE = 3;
		public static $PUT = 4;
		public static $PATCH = 5;

		/** @var string Connector folder directory */
		public $dir = __DIR__;

		/** @var string Autonami integration class name */
		public $autonami_int_slug = '';

		/** @var null Nice name */
		public $nice_name = null;

		/** @var bool Connector has settings */
		public $is_setting = true;

		/** @var string Public directory URL */
		protected $connector_url = '';

		/** @var array Connector keys which are tracked during syncing and update */
		protected $keys_to_track = [];
		protected $form_req_keys = [];
		protected $sync = false;
		protected $is_oauth = false;

		/** @var bool Connector is available for pro: default true */
		public $is_pro = true;

		/** @var bool If connector is configured through a direct url */
		public $direct_connect = false;
		public $is_new = 0;

		protected $priority = 10;

		/**
		 * Loads all calls of current connector
		 */
		public function load_calls() {
			$resource_dir = $this->dir . '/calls';
			if ( @file_exists( $resource_dir ) ) {
				foreach ( glob( $resource_dir . '/class-*.php' ) as $filename ) {
					$call_class = require_once( $filename );
					if ( ( is_object( $call_class ) || is_string( $call_class ) ) && method_exists( $call_class, 'get_instance' ) ) {
						$call_obj = $call_class::get_instance();
						$call_obj->set_connector_slug( $this->get_slug() );
						WFCO_Load_Connectors::register_calls( $call_obj );
					}
				}
			}

			do_action( 'bwfan_' . $this->get_slug() . '_actions_loaded' );
		}

		public function get_slug() {
			return sanitize_title( get_class( $this ) );
		}

		/**
		 * Handles the settings form submission
		 *
		 * @param $data
		 * @param string $type
		 *
		 * @return $array
		 */
		public function handle_settings_form( $data, $type = 'save' ) {
			$old_data = [];
			$new_data = [];

			$status = 'failed';
			$resp   = array(
				'status'  => $status,
				'id'      => 0,
				'message' => '',
			);

			/** Validating form settings */
			if ( 'sync' !== $type ) {
				$is_valid = $this->validate_settings_fields( $data, $type );
				if ( false === $is_valid ) {
					$resp['message'] = $this->get_connector_messages( 'connector_settings_missing' );

					return $resp;
				}
			}

			switch ( $type ) {
				case 'save':
					$new_data = $this->get_api_data( $data );
					if ( is_array( $new_data['api_data'] ) && count( $new_data['api_data'] ) > 0 && isset( $new_data['status'] ) && 'failed' !== $new_data['status'] ) {
						$id = WFCO_Common::save_connector_data( $new_data['api_data'], $this->get_slug(), 1 );

						$resp['id']      = $id;
						$resp['message'] = $this->get_connector_messages( 'connector_saved' );
					}
					break;
				case 'update':
					$saved_data = WFCO_Common::$connectors_saved_data;
					$old_data   = $saved_data[ $this->get_slug() ];
					$new_data   = $this->get_api_data( $data );

					if ( isset( $new_data['status'] ) && 'success' === $new_data['status'] ) {
						$resp['message'] = $this->get_connector_messages( 'connector_updated' );
					}
					break;
				case 'sync':
					$saved_data = WFCO_Common::$connectors_saved_data;
					$old_data   = $saved_data[ $this->get_slug() ];
					$new_data   = $this->get_api_data( $old_data );

					if ( isset( $new_data['status'] ) && 'success' === $new_data['status'] ) {
						$resp['message'] = $this->get_connector_messages( 'connector_synced' );
					}
					break;
			}

			$resp['status'] = $this->get_response_status( $new_data, 'status' );
			if ( '' === $resp['message'] && isset( $new_data['message'] ) && '' !== $new_data['message'] ) {
				$resp['message'] = $new_data['message'];
			}

			$resp['data_changed'] = 0;

			/** Return for save type case */
			if ( 'save' === $type ) {
				return $resp;
			}

			/** Assigning ID */
			$resp['id'] = $data['id'];

			/** Saving new data */
			WFCO_Common::update_connector_data( $new_data['api_data'], $resp['id'] );

			/** Tracking if data changed */
			$is_data_changed = $this->track_sync_changes( $new_data['api_data'], $old_data );
			if ( true === $is_data_changed ) {
				do_action( 'change_in_connector_data', $this->get_slug() );
				$resp['data_changed'] = 1;
			}

			return $resp;
		}

		/**
		 * Validating connector form settings fields, all required fields should be present with values
		 *
		 * @param $data
		 * @param string $type
		 *
		 * @return boolean
		 *
		 * @todo empty values need to check
		 */
		protected function validate_settings_fields( $data, $type = 'save' ) {
			$available_keys = array_keys( $data );
			if ( 'save' !== $type ) {
				$available_keys[] = 'id';
			}

			$diff = array_diff( $this->form_req_keys, $available_keys );
			if ( count( $diff ) > 0 ) {
				return false;
			}

			return true;
		}

		public function get_connector_messages( $key = 'connector_saved' ) {
			$messages = array(
				'connector_saved'            => __( 'Connector saved successfully', 'woofunnels' ), // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
				'connector_synced'           => __( 'Connector synced successfully', 'woofunnels' ),  // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
				'connector_updated'          => __( 'Connector updated successfully', 'woofunnels' ),  // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
				'connector_settings_missing' => __( 'Connector settings missing', 'woofunnels' ),  // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
			);

			return ( isset( $messages[ $key ] ) ) ? $messages[ $key ] : '';
		}

		/**
		 * Get data from the API call, must required function otherwise call
		 *
		 * @param $data
		 *
		 * @return array
		 */
		protected function get_api_data( $data ) {
			return array(
				'status'  => 'failed',
				'message' => __( 'Connector forgot to override the method - get_api_data.', 'woofunnels' ),  // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
			);
		}

		public function get_response_status( $data, $key = 'status' ) {
			$value = ( isset( $data[ $key ] ) ) ? $data[ $key ] : '';
			$value = ( 'status' === $key && empty( $value ) ) ? 'failed' : $value;

			return $value;
		}

		/**
		 * Track connector old and new data and return if any data change detected.
		 *
		 * @param $new_data
		 * @param $old_data
		 *
		 * @return bool
		 */
		protected function track_sync_changes( $new_data, $old_data ) {
			$has_changes = false;

			if ( empty( $this->keys_to_track ) || empty( $new_data ) || empty( $old_data ) ) {
				return $has_changes;
			}

			foreach ( $this->keys_to_track as $key ) {
				$str1 = isset( $new_data[ $key ] ) ? $new_data[ $key ] : '';
				$str2 = isset( $old_data[ $key ] ) ? $old_data[ $key ] : '';
				$str1 = is_array( $str1 ) ? wp_json_encode( $str1 ) : $str1;
				$str2 = is_array( $str2 ) ? wp_json_encode( $str2 ) : $str2;

				$diff = strcmp( $str1, $str2 );
				if ( 0 === $diff ) {
					continue;
				}
				$has_changes = true;
				break;
			}

			return $has_changes;
		}

		public function get_image() {
			return $this->connector_url . '/views/logo.png';
		}

		public function has_settings() {
			return $this->is_setting;
		}

		public function is_syncable() {
			return $this->sync;
		}

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

		/**
		 * Get the connector loading priority
		 *
		 * @return int|mixed
		 */
		public function get_priority() {
			return $this->priority;
		}
	}
}