<?php
/**
 * Keap Transformer
 *
 * Custom transformer for Keap (formerly InfusionSoft) integration
 * Handles the specific email_addresses array structure required by Keap API
 *
 * @package SureForms
 * @since 2.3.0
 */

namespace SRFM_Pro\Inc\Pro\Native_Integrations\Transformers;

use SRFM\Inc\Helper;
use SRFM_Pro\Inc\Pro\Native_Integrations\Interfaces\Payload_Transformer;
use SRFM_Pro\Inc\Pro\Native_Integrations\OAuth_Handler;
use SRFM_Pro\Inc\Pro\Native_Integrations\Services\Config_Manager;
use SRFM_Pro\Inc\Pro\Native_Integrations\Services\Workflow_Processor;
use SRFM_Pro\Inc\Pro\Native_Integrations\Utils\Integration_Utils;

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

/**
 * Keap Transformer class.
 *
 * @since 2.3.0
 */
class Keap_Transformer implements Payload_Transformer {
	/**
	 * Integration name
	 *
	 * @var string
	 */
	private $integration_name = 'keap';

	/**
	 * Get integration name this transformer handles
	 *
	 * @return string Integration name.
	 * @since 2.3.0
	 */
	public function get_integration_name() {
		return $this->integration_name;
	}

	/**
	 * Transform payload for Keap integration
	 *
	 * Transforms the flat form data into Keap's required structure:
	 * - Converts email field to email_addresses array with proper structure
	 * - Handles phone numbers transformation if present
	 * - Maps field names to Keap API requirements
	 *
	 * @param array $form_data Original form data.
	 * @param array $field_mappings Field mappings configuration.
	 * @param array $context Additional context data.
	 * @return array Transformed payload for Keap API.
	 * @since 2.3.0
	 */
	public function transform( $form_data, $field_mappings = [], $context = [] ) {
		unset( $field_mappings ); // Not used in this implementation.
		// Initialize the transformed payload.
		$payload = [];

		// Check if this is a note creation action.
		if ( ! empty( $form_data['title'] ) && ! empty( $form_data['body'] ) && ! empty( $form_data['contact_email'] ) ) {
			return $this->transform_note_payload( $form_data, $context );
		}

		// Check if this is a company creation action.
		if ( ! empty( $form_data['company_name'] ) ) {
			return $this->transform_company_payload( $form_data );
		}

		// Handle Keap-specific control fields.
		if ( ! empty( $form_data['how_to'] ) ) {
			$payload['duplicate_option'] = Helper::get_string_value( $form_data['how_to'] );
		}

		if ( isset( $form_data['opted_in'] ) ) {
			$payload['opt_in_reason'] = 'true' === $form_data['opted_in'] || true === $form_data['opted_in'] ?
				'Customer opted-in via web form' : 'Customer did not opt-in';
		}

		// Handle email field - convert to email_addresses array.
		if ( ! empty( $form_data['email'] ) ) {
			$payload['email_addresses'] = [
				[
					'email' => Helper::get_string_value( $form_data['email'] ),
					'field' => 'EMAIL1',
				],
			];
		}

		// Handle name fields.
		if ( ! empty( $form_data['given_name'] ) ) {
			$payload['given_name'] = Helper::get_string_value( $form_data['given_name'] );
		}

		if ( ! empty( $form_data['family_name'] ) ) {
			$payload['family_name'] = Helper::get_string_value( $form_data['family_name'] );
		}

		// Handle phone numbers - convert to phone_numbers array if present.
		if ( ! empty( $form_data['phone'] ) ) {
			$payload['phone_numbers'] = [
				[
					'number' => Helper::get_string_value( $form_data['phone'] ),
					'field'  => 'PHONE1',
				],
			];
		}

		// Handle other standard fields that map directly.
		$direct_mapping_fields = [
			'job_title',
			'website',
		];

		foreach ( $direct_mapping_fields as $field ) {
			if ( ! empty( $form_data[ $field ] ) ) {
				$payload[ $field ] = Helper::get_string_value( $form_data[ $field ] );
			}
		}

		// Handle company field - map company_name to company object.
		if ( ! empty( $form_data['company_name'] ) ) {
			$payload['company'] = [
				'company_name' => Helper::get_string_value( $form_data['company_name'] ),
			];
		}

		// Handle billing address fields - convert to addresses array if present.
		$billing_address_fields = [
			'line1'    => $form_data['billing_address_1'] ?? $form_data['address_line1'] ?? $form_data['addr1'] ?? '',
			'line2'    => $form_data['billing_address_2'] ?? $form_data['address_line2'] ?? $form_data['addr2'] ?? '',
			'locality' => $form_data['b_city'] ?? $form_data['city'] ?? '',
			'zip_code' => $form_data['b_zip_code'] ?? $form_data['zip'] ?? $form_data['postal_code'] ?? '',
		];

		// Only add addresses array if we have at least one billing address field.
		$has_billing_address = false;
		$billing_address     = [ 'field' => 'BILLING' ];
		foreach ( $billing_address_fields as $keap_field => $value ) {
			if ( ! empty( $value ) ) {
				$billing_address[ $keap_field ] = Helper::get_string_value( $value );
				$has_billing_address            = true;
			}
		}

		if ( $has_billing_address ) {
			$payload['addresses'] = [ $billing_address ];
		}

		// Handle special date fields (birthday, anniversary).
		if ( ! empty( $form_data['birthday'] ) ) {
			$payload['birthday'] = $this->format_date_for_keap( $form_data['birthday'] );
		}

		if ( ! empty( $form_data['anniversary'] ) ) {
			$payload['anniversary'] = $this->format_date_for_keap( $form_data['anniversary'] );
		}

		// Handle custom fields - any field not in the standard mapping gets added as custom field.
		$standard_fields = [
			'email',
			'how_to',
			'opted_in',
			'given_name',
			'family_name',
			'phone',
			'company_name',
			'job_title',
			'website',
			'billing_address_1',
			'billing_address_2',
			'b_city',
			'b_state',
			'b_zip_code',
			'b_zip_country',
			'address_line1',
			'addr1',
			'address_line2',
			'addr2',
			'city',
			'state',
			'zip',
			'postal_code',
			'country',
			'birthday',
			'anniversary',
		];

		$custom_fields = [];
		foreach ( $form_data as $field_key => $field_value ) {
			if ( ! in_array( $field_key, $standard_fields, true ) && ! empty( $field_value ) ) {
				$custom_fields[] = [
					'content' => Helper::get_string_value( $field_value ),
					'id'      => $this->map_custom_field_id( $field_key ),
				];
			}
		}

		if ( ! empty( $custom_fields ) ) {
			$payload['custom_fields'] = $custom_fields;
		}

		return $payload;
	}

	/**
	 * Prepare test payload with sample data
	 *
	 * @param array $workflow_fields Fields from the workflow configuration.
	 * @param array $field_definitions Field definitions from the action configuration.
	 * @return array Test payload.
	 * @since 2.3.0
	 */
	public function prepare_test_payload( $workflow_fields, $field_definitions ) {
		$payload = Workflow_Processor::prepare_test_payload( $workflow_fields, $field_definitions );

		// Transform with test mode indicator to show realistic test data.
		return $this->transform( $payload, [], [ 'test_mode' => true ] );
	}

	/**
	 * Transform payload for note creation
	 *
	 * @param array $form_data Original form data.
	 * @param array $context Additional context data including access token.
	 * @return array Transformed payload for Keap note API.
	 * @since 2.3.0
	 */
	private function transform_note_payload( $form_data, $context = [] ) {
		$payload = [
			'title' => Helper::get_string_value( $form_data['title'] ),
			'body'  => Helper::get_string_value( $form_data['body'] ),
		];

		// Handle contact ID - need lookup via email.
		if ( ! empty( $form_data['contact_email'] ) ) {
			$context['config_manager'] = new Config_Manager();
			$context['oauth_handler']  = new OAuth_Handler( $context['config_manager'] );

			$contact_id = $this->lookup_contact_id_by_email( $form_data['contact_email'], $context );
			if ( $contact_id ) {
				$payload['contact_id'] = intval( $contact_id );
			} else {
				// If lookup fails, we cannot create the note.
				return [];
			}
		} else {
			// No contact email provided.
			return [];
		}

		// Add note type if provided.
		if ( ! empty( $form_data['type'] ) ) {
			$payload['type'] = Helper::get_string_value( $form_data['type'] );
		}

		return $payload;
	}

	/**
	 * Lookup contact ID by email address
	 *
	 * @param string $email Contact email address.
	 * @param array  $context Context data containing OAuth dependencies.
	 * @return int|null Contact ID or null if not found.
	 * @since 2.3.0
	 */
	private function lookup_contact_id_by_email( $email, $context = [] ) {
		// Get OAuth dependencies from context.
		$oauth_handler  = $context['oauth_handler'] ?? null;
		$config_manager = $context['config_manager'] ?? null;
		$auth_config    = $context['auth_config'] ?? [];

		// Get credentials with OAuth token refresh support.
		$credentials = Integration_Utils::get_stored_credentials(
			$this->integration_name,
			$auth_config,
			$oauth_handler,
			$config_manager
		);

		if ( is_wp_error( $credentials ) || ! $credentials ) {
			return null;
		}

		$access_token = $credentials['access_token'] ?? '';
		if ( empty( $access_token ) || empty( $email ) ) {
			return null;
		}

		$email      = Helper::get_string_value( $email );
		$lookup_url = 'https://api.infusionsoft.com/crm/rest/v1/contacts?email=' . rawurlencode( $email );

		$response = wp_remote_get(
			$lookup_url,
			[
				'headers' => [
					'Authorization' => 'Bearer ' . $access_token,
					'Content-Type'  => 'application/json',
				],
				'timeout' => 30,
			]
		);

		if ( is_wp_error( $response ) ) {
			return null;
		}

		$status_code = wp_remote_retrieve_response_code( $response );
		if ( 200 !== $status_code ) {
			return null;
		}

		$body = wp_remote_retrieve_body( $response );
		$data = json_decode( $body, true );

		// Ensure $data is an array and contains a contacts array.
		if ( json_last_error() !== JSON_ERROR_NONE || ! is_array( $data ) || empty( $data['contacts'] ) || ! is_array( $data['contacts'] ) ) {
			return null;
		}

		// Safely pull ID from the first contact.
		$contact_id = $data['contacts'][0]['id'] ?? null;

		return ! empty( $contact_id ) ? $contact_id : null;
	}

	/**
	 * Transform payload for company creation
	 *
	 * @param array $form_data Original form data.
	 * @return array Transformed payload for Keap company API.
	 * @since 2.3.0
	 */
	private function transform_company_payload( $form_data ) {
		$payload = [
			'company_name' => Helper::get_string_value( $form_data['company_name'] ),
		];

		// Handle phone number - convert to proper object structure.
		if ( ! empty( $form_data['phone_number'] ) ) {
			$phone_object = [
				'number' => Helper::get_string_value( $form_data['phone_number'] ),
				'type'   => 'Work',
			];

			// Add extension if provided.
			if ( ! empty( $form_data['phone_ext'] ) ) {
				$phone_object['extension'] = Helper::get_string_value( $form_data['phone_ext'] );
			}

			$payload['phone_number'] = $phone_object;
		}

		// Handle fax number.
		if ( ! empty( $form_data['fax_number'] ) ) {
			$payload['fax_number'] = [
				'number' => Helper::get_string_value( $form_data['fax_number'] ),
				'type'   => 'Work',
			];
		}

		// Handle address - convert to proper address object structure.
		$address_fields = [
			'line1'    => $form_data['address1'] ?? '',
			'line2'    => $form_data['address2'] ?? '',
			'locality' => $form_data['city'] ?? '',
			'zip_code' => $form_data['postal_code'] ?? '',
		];

		// Only add address if we have at least one address field.
		$has_address = false;
		$address     = [];
		foreach ( $address_fields as $address_field => $value ) {
			if ( ! empty( $value ) ) {
				$address[ $address_field ] = Helper::get_string_value( $value );
				$has_address               = true;
			}
		}

		if ( $has_address ) {
			$payload['address'] = $address;
		}

		// Handle other direct mapping fields.
		$direct_mapping_fields = [
			'email_address' => 'email_address',
			'website'       => 'website',
		];

		foreach ( $direct_mapping_fields as $form_field => $api_field ) {
			if ( ! empty( $form_data[ $form_field ] ) ) {
				$payload[ $api_field ] = Helper::get_string_value( $form_data[ $form_field ] );
			}
		}

		return $payload;
	}

	/**
	 * Map custom field key to Keap custom field ID
	 *
	 * This is a simplified mapping. In a real implementation, you might want to:
	 * - Fetch actual custom field IDs from Keap API
	 * - Store mapping in WordPress options
	 * - Provide UI for users to map fields
	 *
	 * @param string $field_key Form field key.
	 * @return int Custom field ID for Keap.
	 * @since 2.3.0
	 */
	private function map_custom_field_id( $field_key ) {
		// Default mapping - you would replace this with actual custom field IDs from Keap.
		$custom_field_mapping = [
			'notes'       => 1,
			'source'      => 2,
			'lead_source' => 3,
			'description' => 4,
		];

		// Return mapped ID or default to 1.
		return $custom_field_mapping[ $field_key ] ?? 1;
	}

	/**
	 * Format date for Keap API
	 *
	 * Keap expects dates in ISO 8601 format: YYYY-MM-DDTHH:mm:ss.sssZ
	 *
	 * @param string $date_value Date value from form.
	 * @return string Formatted date for Keap.
	 * @since 2.3.0
	 */
	private function format_date_for_keap( $date_value ) {
		$date_string = Helper::get_string_value( $date_value );

		// If already in ISO format, return as-is.
		if ( preg_match( '/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/', $date_string ) ) {
			return $date_string;
		}

		// Try to parse the date and format it properly.
		$timestamp = strtotime( $date_string );
		if ( false !== $timestamp ) {
			return gmdate( 'Y-m-d\TH:i:s.000\Z', $timestamp );
		}

		// If parsing fails, return the original value.
		return $date_string;
	}
}
