<?php
/**
 * Mailchimp Marketing API v3 integration.
 *
 * @package TonItaliaRegistration
 */

defined( 'ABSPATH' ) || exit;

/**
 * Class TON_Reg_Mailchimp
 */
class TON_Reg_Mailchimp {

	const CRON_HOOK = 'ton_reg_mailchimp_sync';

	/**
	 * @return bool
	 */
	public static function is_configured() {
		return '1' === get_option( 'ton_reg_mailchimp_enabled', '0' )
			&& '' !== self::get_api_key()
			&& '' !== self::get_list_id();
	}

	/**
	 * @return string
	 */
	public static function get_api_key() {
		return (string) get_option( 'ton_reg_mailchimp_api_key', '' );
	}

	/**
	 * @return string
	 */
	public static function get_list_id() {
		$list_id = (string) get_option( 'ton_reg_mailchimp_list_id', '' );
		if ( ! self::is_valid_list_id( $list_id ) ) {
			return '';
		}
		return $list_id;
	}

	/**
	 * @param string $list_id List ID.
	 * @return bool
	 */
	public static function is_valid_list_id( $list_id ) {
		return (bool) preg_match( '/^[a-f0-9]{8,12}$/i', (string) $list_id );
	}

	/**
	 * @param int $registration_id Registration ID.
	 */
	public static function schedule_sync( $registration_id ) {
		$registration_id = (int) $registration_id;
		if ( $registration_id <= 0 ) {
			return;
		}

		TON_Reg_Database::update(
			$registration_id,
			array(
				'mailchimp_status' => 'pending',
				'mailchimp_error'  => null,
			)
		);

		wp_schedule_single_event( time(), self::CRON_HOOK, array( $registration_id ) );
	}

	/**
	 * @param int $registration_id Registration ID.
	 * @return bool True on success.
	 */
	public static function sync_registration( $registration_id ) {
		$registration_id = (int) $registration_id;
		$row             = TON_Reg_Database::get( $registration_id );

		if ( ! $row ) {
			return false;
		}

		if ( empty( $row->consenso_newsletter ) ) {
			self::record_status( $registration_id, 'skipped', '' );
			return true;
		}

		if ( ! self::is_configured() ) {
			self::record_status( $registration_id, 'skipped', '' );
			return true;
		}

		$email = sanitize_email( $row->email );
		if ( ! is_email( $email ) ) {
			self::record_status( $registration_id, 'error', __( 'Email non valida per Mailchimp.', 'ton-italia-registration' ) );
			return false;
		}

		$subscriber_hash = self::subscriber_hash( $email );
		$list_id         = self::get_list_id();
		$merge_fields    = array(
			'FNAME' => self::truncate_merge_field( $row->nome ?? '' ),
			'LNAME' => self::truncate_merge_field( $row->cognome ?? '' ),
		);

		$body = array(
			'email_address' => $email,
			'status_if_new' => 'subscribed',
			'merge_fields'  => $merge_fields,
		);

		$permissions = self::get_marketing_permissions_payload();
		if ( ! empty( $permissions ) ) {
			$body['marketing_permissions'] = $permissions;
		}

		$put = self::api_request(
			'PUT',
			'/lists/' . $list_id . '/members/' . $subscriber_hash,
			$body
		);

		if ( is_wp_error( $put ) ) {
			self::record_status( $registration_id, 'error', $put->get_error_message() );
			self::debug_log( 'Mailchimp PUT failed for registration ' . $registration_id );
			return false;
		}

		$member_status = isset( $put['status'] ) ? (string) $put['status'] : '';

		if ( 'cleaned' === $member_status ) {
			self::record_status(
				$registration_id,
				'error',
				__( 'Contatto in stato cleaned in Mailchimp — gestione manuale richiesta.', 'ton-italia-registration' )
			);
			return false;
		}

		if ( 'unsubscribed' === $member_status ) {
			$patch_body = array( 'status' => 'subscribed' );
			if ( ! empty( $permissions ) ) {
				$patch_body['marketing_permissions'] = $permissions;
			}

			$patch = self::api_request(
				'PATCH',
				'/lists/' . $list_id . '/members/' . $subscriber_hash,
				$patch_body
			);

			if ( is_wp_error( $patch ) ) {
				self::record_status( $registration_id, 'error', $patch->get_error_message() );
				self::debug_log( 'Mailchimp PATCH failed for registration ' . $registration_id );
				return false;
			}

			$member_status = isset( $patch['status'] ) ? (string) $patch['status'] : $member_status;
		}

		$tags = self::parse_tags();
		if ( ! empty( $tags ) ) {
			$tag_result = self::api_request(
				'POST',
				'/lists/' . $list_id . '/members/' . $subscriber_hash . '/tags',
				array(
					'tags' => array_map(
						static function ( $name ) {
							return array(
								'name'   => $name,
								'status' => 'active',
							);
						},
						$tags
					),
				)
			);

			if ( is_wp_error( $tag_result ) ) {
				self::record_status( $registration_id, 'error', $tag_result->get_error_message() );
				self::debug_log( 'Mailchimp tags failed for registration ' . $registration_id );
				return false;
			}
		}

		if ( 'subscribed' !== $member_status && 'pending' !== $member_status ) {
			self::record_status(
				$registration_id,
				'error',
				sprintf(
					/* translators: %s: Mailchimp member status */
					__( 'Stato Mailchimp inatteso: %s', 'ton-italia-registration' ),
					$member_status
				)
			);
			return false;
		}

		self::record_status( $registration_id, 'synced', '' );
		return true;
	}

	/**
	 * Test API credentials and list access; cache marketing permission IDs.
	 *
	 * @param string $api_key_override Optional API key from unsaved form.
	 * @param string $list_id_override Optional list ID from unsaved form.
	 * @return true|WP_Error
	 */
	public static function test_connection( $api_key_override = '', $list_id_override = '' ) {
		$api_key = '' !== (string) $api_key_override ? (string) $api_key_override : self::get_api_key();
		$list_id = '' !== (string) $list_id_override ? (string) $list_id_override : (string) get_option( 'ton_reg_mailchimp_list_id', '' );

		if ( '' !== (string) $api_key_override && ! preg_match( '/^.+-[a-z]{2}\d+$/i', (string) $api_key_override ) ) {
			return new WP_Error( 'mailchimp', __( 'Formato API key Mailchimp non valido (atteso: chiave-us12).', 'ton-italia-registration' ) );
		}

		if ( '' !== (string) $api_key && ! preg_match( '/^.+-[a-z]{2}\d+$/i', (string) $api_key ) ) {
			return new WP_Error( 'mailchimp', __( 'Formato API key Mailchimp non valido (atteso: chiave-us12).', 'ton-italia-registration' ) );
		}

		if ( '' === $api_key ) {
			return new WP_Error( 'mailchimp', __( 'API key Mailchimp non configurata.', 'ton-italia-registration' ) );
		}

		if ( ! self::is_valid_list_id( $list_id ) ) {
			return new WP_Error( 'mailchimp', __( 'List ID Mailchimp non valido.', 'ton-italia-registration' ) );
		}

		$ping = self::api_request_with_key( 'GET', '/ping', null, $api_key );
		if ( is_wp_error( $ping ) ) {
			return $ping;
		}

		$list = self::api_request_with_key( 'GET', '/lists/' . $list_id, null, $api_key );
		if ( is_wp_error( $list ) ) {
			return $list;
		}

		$permission_ids = self::extract_permission_ids_from_list( $list );
		update_option( 'ton_reg_mailchimp_permission_ids', wp_json_encode( $permission_ids ), false );

		return true;
	}

	/**
	 * Keep API key out of autoloaded options snapshot.
	 */
	public static function ensure_api_key_no_autoload() {
		global $wpdb;

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->update(
			$wpdb->options,
			array( 'autoload' => 'no' ),
			array( 'option_name' => 'ton_reg_mailchimp_api_key' ),
			array( '%s' ),
			array( '%s' )
		);
	}

	/**
	 * @param string $email Email.
	 * @return string
	 */
	public static function subscriber_hash( $email ) {
		return md5( strtolower( trim( (string) $email ) ) );
	}

	/**
	 * @param string $value Merge field value.
	 * @return string
	 */
	private static function truncate_merge_field( $value ) {
		$value = sanitize_text_field( (string) $value );
		if ( function_exists( 'mb_substr' ) ) {
			return mb_substr( $value, 0, 100 );
		}
		return substr( $value, 0, 100 );
	}

	/**
	 * @return array<int,array<string,mixed>>
	 */
	private static function get_marketing_permissions_payload() {
		$raw = (string) get_option( 'ton_reg_mailchimp_permission_ids', '[]' );
		$ids = json_decode( $raw, true );
		if ( ! is_array( $ids ) || empty( $ids ) ) {
			return array();
		}

		$payload = array();
		foreach ( $ids as $id ) {
			$id = sanitize_text_field( (string) $id );
			if ( '' !== $id ) {
				$payload[] = array(
					'marketing_permission_id' => $id,
					'enabled'                 => true,
				);
			}
		}

		return $payload;
	}

	/**
	 * @return array<int,string>
	 */
	private static function parse_tags() {
		$raw  = (string) get_option( 'ton_reg_mailchimp_tags', 'Socio TON ITALIA' );
		$tags = array_map( 'trim', explode( ',', $raw ) );
		$tags = array_filter(
			array_map( 'sanitize_text_field', $tags ),
			static function ( $tag ) {
				return '' !== $tag;
			}
		);

		return array_slice( array_values( $tags ), 0, 5 );
	}

	/**
	 * @param array<string,mixed> $list List API response.
	 * @return array<int,string>
	 */
	private static function extract_permission_ids_from_list( $list ) {
		$ids = array();

		if ( ! empty( $list['marketing_permissions'] ) && is_array( $list['marketing_permissions'] ) ) {
			foreach ( $list['marketing_permissions'] as $permission ) {
				if ( ! empty( $permission['marketing_permission_id'] ) ) {
					$ids[] = sanitize_text_field( (string) $permission['marketing_permission_id'] );
				}
			}
		}

		return array_values( array_unique( $ids ) );
	}

	/**
	 * @param string               $method HTTP method.
	 * @param string               $path   API path starting with /.
	 * @param array<string,mixed>|null $body   Request body.
	 * @return array<string,mixed>|WP_Error
	 */
	private static function api_request( $method, $path, $body = null ) {
		return self::api_request_with_key( $method, $path, $body, self::get_api_key() );
	}

	/**
	 * @param string               $method HTTP method.
	 * @param string               $path   API path starting with /.
	 * @param array<string,mixed>|null $body   Request body.
	 * @param string               $api_key API key.
	 * @return array<string,mixed>|WP_Error
	 */
	private static function api_request_with_key( $method, $path, $body, $api_key ) {
		$dc = self::extract_datacenter( $api_key );

		if ( ! $dc ) {
			return new WP_Error( 'mailchimp', __( 'API key Mailchimp non valida.', 'ton-italia-registration' ) );
		}

		$url  = 'https://' . $dc . '.api.mailchimp.com/3.0' . $path;
		$args = array(
			'method'  => strtoupper( $method ),
			'timeout' => 10,
			'headers' => array(
				'Authorization' => 'Basic ' . base64_encode( 'ton_reg:' . $api_key ),
				'Content-Type'  => 'application/json',
			),
		);

		if ( null !== $body ) {
			$args['body'] = wp_json_encode( $body );
		}

		$response = wp_remote_request( $url, $args );
		if ( is_wp_error( $response ) ) {
			return new WP_Error( 'mailchimp', __( 'Impossibile contattare Mailchimp.', 'ton-italia-registration' ) );
		}

		$code = (int) wp_remote_retrieve_response_code( $response );
		$raw  = wp_remote_retrieve_body( $response );
		$data = json_decode( $raw, true );

		if ( $code < 200 || $code >= 300 ) {
			return new WP_Error( 'mailchimp', self::parse_api_error( $data, $code ) );
		}

		return is_array( $data ) ? $data : array();
	}

	/**
	 * @param mixed $data Response JSON.
	 * @param int   $code HTTP code.
	 * @return string
	 */
	private static function parse_api_error( $data, $code ) {
		$message = sprintf(
			/* translators: %d: HTTP status code */
			__( 'Errore Mailchimp (HTTP %d).', 'ton-italia-registration' ),
			$code
		);

		if ( is_array( $data ) ) {
			if ( ! empty( $data['detail'] ) && is_string( $data['detail'] ) ) {
				$message = sanitize_text_field( $data['detail'] );
			} elseif ( ! empty( $data['title'] ) && is_string( $data['title'] ) ) {
				$message = sanitize_text_field( $data['title'] );
			}
		}

		if ( function_exists( 'mb_substr' ) ) {
			return mb_substr( $message, 0, 255 );
		}

		return substr( $message, 0, 255 );
	}

	/**
	 * @param string $api_key API key.
	 * @return string Empty if invalid.
	 */
	private static function extract_datacenter( $api_key ) {
		if ( ! preg_match( '/-([a-z]{2}\d+)$/', (string) $api_key, $matches ) ) {
			return '';
		}
		return $matches[1];
	}

	/**
	 * @param int    $registration_id Registration ID.
	 * @param string $status          Status slug.
	 * @param string $error           Error message.
	 */
	private static function record_status( $registration_id, $status, $error ) {
		$data = array(
			'mailchimp_status' => sanitize_text_field( $status ),
			'mailchimp_error'  => '' !== $error ? sanitize_text_field( $error ) : null,
		);

		if ( 'synced' === $status ) {
			$data['mailchimp_synced_at'] = current_time( 'mysql', true );
		}

		TON_Reg_Database::update( $registration_id, $data );
	}

	/**
	 * @param string $message Log message without PII.
	 */
	private static function debug_log( $message ) {
		if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
			// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
			error_log( '[ton-italia-registration] ' . $message );
		}
	}

	/**
	 * @param mixed $value Submitted API key.
	 * @return string
	 */
	public static function sanitize_api_key( $value ) {
		$value = sanitize_text_field( wp_unslash( (string) $value ) );
		$old   = (string) get_option( 'ton_reg_mailchimp_api_key', '' );

		if ( '' === $value ) {
			return $old;
		}

		if ( ! preg_match( '/^.+-[a-z]{2}\d+$/i', $value ) ) {
			add_settings_error(
				'ton_reg_mailchimp_api_key',
				'invalid_mailchimp_api_key',
				__( 'Formato API key Mailchimp non valido.', 'ton-italia-registration' ),
				'error'
			);
			return $old;
		}

		return $value;
	}

	/**
	 * @param mixed $value Submitted list ID.
	 * @return string
	 */
	public static function sanitize_list_id( $value ) {
		$value = sanitize_text_field( wp_unslash( (string) $value ) );
		if ( '' === $value || self::is_valid_list_id( $value ) ) {
			return $value;
		}

		add_settings_error(
			'ton_reg_mailchimp_list_id',
			'invalid_mailchimp_list_id',
			__( 'List ID Mailchimp non valido.', 'ton-italia-registration' ),
			'error'
		);

		return (string) get_option( 'ton_reg_mailchimp_list_id', '' );
	}
}
