<?php

declare(strict_types=1);

namespace FormConnector\Integration\Forms;

/**
 * Form Integration Manager
 * 
 * Detects installed form plugins and provides unified access to their forms and fields.
 * Supports: Gravity Forms, Contact Form 7, WPForms, Forminator, Fluent Forms
 */
class FormIntegrationManager {

	/**
	 * Singleton instance
	 */
	private static ?FormIntegrationManager $instance = null;

	/**
	 * Cached forms data
	 */
	private ?array $forms_cache = null;

	/**
	 * Get singleton instance
	 */
	public static function get_instance(): self {
		if (self::$instance === null) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Private constructor
	 */
	private function __construct() {}

	/**
	 * Get all supported form plugins and their status
	 */
	public function get_plugins(): array {
		return [
			'gravityforms' => [
				'name' => 'Gravity Forms',
				'active' => class_exists('GFAPI'),
				'color' => '#f15a29',
			],
			'cf7' => [
				'name' => 'Contact Form 7',
				'active' => class_exists('WPCF7'),
				'color' => '#0073aa',
			],
			'wpforms' => [
				'name' => 'WPForms',
				'active' => function_exists('wpforms'),
				'color' => '#e27730',
			],
			'forminator' => [
				'name' => 'Forminator',
				'active' => class_exists('Forminator_API'),
				'color' => '#17a8e3',
			],
			'fluentforms' => [
				'name' => 'Fluent Forms',
				'active' => defined('FLUENTFORM'),
				'color' => '#4b4dff',
			],
		];
	}

	/**
	 * Get all active form plugins
	 */
	public function get_active_plugins(): array {
		return array_filter($this->get_plugins(), fn($p) => $p['active']);
	}

	/**
	 * Get all forms from all active plugins
	 */
	public function get_all_forms(): array {
		if ($this->forms_cache !== null) {
			return $this->forms_cache;
		}

		$all_forms = [];
		$plugins = $this->get_plugins();

		foreach ($plugins as $key => $plugin) {
			if (!$plugin['active']) {
				continue;
			}

			$forms = $this->get_plugin_forms($key);
			foreach ($forms as $form) {
				$form['plugin'] = $key;
				$form['plugin_name'] = $plugin['name'];
				$form['plugin_color'] = $plugin['color'];
				$all_forms[] = $form;
			}
		}

		// Sort by name
		usort($all_forms, fn($a, $b) => strcasecmp($a['name'], $b['name']));

		$this->forms_cache = $all_forms;
		return $all_forms;
	}

	/**
	 * Get forms for a specific plugin
	 */
	public function get_plugin_forms(string $plugin): array {
		return match ($plugin) {
			'gravityforms' => $this->get_gravityforms_forms(),
			'cf7' => $this->get_cf7_forms(),
			'wpforms' => $this->get_wpforms_forms(),
			'forminator' => $this->get_forminator_forms(),
			'fluentforms' => $this->get_fluentforms_forms(),
			default => [],
		};
	}

	/**
	 * Get fields for a specific form
	 */
	public function get_form_fields(string $plugin, int|string $form_id): array {
		return match ($plugin) {
			'gravityforms' => $this->get_gravityforms_fields($form_id),
			'cf7' => $this->get_cf7_fields($form_id),
			'wpforms' => $this->get_wpforms_fields($form_id),
			'forminator' => $this->get_forminator_fields($form_id),
			'fluentforms' => $this->get_fluentforms_fields($form_id),
			default => [],
		};
	}

	// ========== GRAVITY FORMS ==========

	private function get_gravityforms_forms(): array {
		if (!class_exists('GFAPI')) {
			return [];
		}

		$forms = \GFAPI::get_forms();
		if (empty($forms)) {
			return [];
		}

		return array_map(fn($form) => [
			'id' => $form['id'],
			'name' => $form['title'],
		], $forms);
	}

	private function get_gravityforms_fields($form_id): array {
		if (!class_exists('GFAPI')) {
			return [];
		}

		$form = \GFAPI::get_form($form_id);
		if (empty($form['fields'])) {
			return [];
		}

		$fields = [];
		foreach ($form['fields'] as $field) {
			$field_type = $field->type ?? '';
			$field_id = (string) $field->id;
			
			// Handle name fields specially - use consistent field_X.Y format
			if ($field_type === 'name') {
				// First name is input 3, last name is input 6 in Gravity Forms
				$fields[] = [
					'id' => 'field_' . $field_id . '.3',
					'label' => ($field->label ?? 'Name') . ' - First Name',
					'type' => 'name-first',
					'options' => [],
				];
				$fields[] = [
					'id' => 'field_' . $field_id . '.6',
					'label' => ($field->label ?? 'Name') . ' - Last Name',
					'type' => 'name-last',
					'options' => [],
				];
				continue;
			}
			
			// Handle address fields
			if ($field_type === 'address') {
				$address_parts = [
					'1' => 'Street Address',
					'2' => 'Address Line 2',
					'3' => 'City',
					'4' => 'State/Province',
					'5' => 'ZIP/Postal Code',
					'6' => 'Country',
				];
				foreach ($address_parts as $part_id => $part_label) {
					$fields[] = [
						'id' => 'field_' . $field_id . '.' . $part_id,
						'label' => ($field->label ?? 'Address') . ' - ' . $part_label,
						'type' => 'address-part',
						'options' => [],
					];
				}
				continue;
			}

			$options = [];
			if (!empty($field->choices)) {
				foreach ($field->choices as $choice) {
					// Handle empty value strings - use text/label as fallback
					$choice_value = !empty($choice['value']) ? $choice['value'] : ($choice['text'] ?? '');
					$choice_label = !empty($choice['text']) ? $choice['text'] : ($choice['value'] ?? '');
					
					$options[] = [
						'value' => $choice_value,
						'label' => $choice_label,
					];
				}
			}

			$fields[] = [
				'id' => 'field_' . $field->id,
				'label' => $field->label ?? 'Field ' . $field->id,
				'type' => $field_type,
				'options' => $options,
			];
		}

		return $fields;
	}

	// ========== CONTACT FORM 7 ==========

	private function get_cf7_forms(): array {
		if (!class_exists('WPCF7')) {
			return [];
		}

		$posts = get_posts([
			'post_type' => 'wpcf7_contact_form',
			'posts_per_page' => -1,
			'orderby' => 'title',
			'order' => 'ASC',
		]);

		return array_map(fn($post) => [
			'id' => $post->ID,
			'name' => $post->post_title,
		], $posts);
	}

	private function get_cf7_fields($form_id): array {
		if (!class_exists('WPCF7_ContactForm')) {
			return [];
		}

		$form = \WPCF7_ContactForm::get_instance($form_id);
		if (!$form) {
			return [];
		}

		$tags = $form->scan_form_tags();
		$fields = [];
		
		// Excluded field types that shouldn't be mapped
		$excluded_types = ['submit', 'hidden', 'captcha', 'recaptcha', 'turnstile', 'quiz'];

		foreach ($tags as $tag) {
			if (empty($tag->name)) {
				continue;
			}
			
			// Skip excluded field types
			if (in_array($tag->basetype, $excluded_types)) {
				continue;
			}

			$options = [];
			if (!empty($tag->values) && in_array($tag->basetype, ['select', 'radio', 'checkbox'])) {
				foreach ($tag->values as $value) {
					$options[] = [
						'value' => $value,
						'label' => $value,
					];
				}
			}
			
			// Create a user-friendly label from the field name
			$label = ucwords(str_replace(['_', '-', 'your-', 'your_'], ' ', $tag->name));
			$label = trim(preg_replace('/\s+/', ' ', $label));

			$fields[] = [
				'id' => $tag->name,
				'label' => $label ?: $tag->name,
				'type' => $tag->basetype,
				'options' => $options,
			];
		}

		return $fields;
	}

	// ========== WPFORMS ==========

	private function get_wpforms_forms(): array {
		if (!function_exists('wpforms')) {
			return [];
		}

		$forms = wpforms()->form->get('', ['orderby' => 'title', 'order' => 'ASC']);
		if (empty($forms)) {
			return [];
		}

		return array_map(fn($form) => [
			'id' => $form->ID,
			'name' => $form->post_title,
		], $forms);
	}

	private function get_wpforms_fields($form_id): array {
		if (!function_exists('wpforms')) {
			return [];
		}

		$form = wpforms()->form->get($form_id);
		if (empty($form)) {
			return [];
		}

		$form_data = wpforms_decode($form->post_content);
		if (empty($form_data['fields'])) {
			return [];
		}

		$fields = [];
		foreach ($form_data['fields'] as $field) {
			$field_id = (string) ($field['id'] ?? '');
			$field_type = $field['type'] ?? '';
			$field_label = $field['label'] ?? 'Field ' . $field_id;
			
			// Skip hidden and submit fields
			if (in_array($field_type, ['hidden', 'pagebreak', 'divider', 'html'])) {
				continue;
			}
			
			// Handle name fields
			if ($field_type === 'name') {
				$fields[] = [
					'id' => 'field_' . $field_id . '_first',
					'label' => $field_label . ' - First Name',
					'type' => 'name-first',
					'options' => [],
				];
				$fields[] = [
					'id' => 'field_' . $field_id . '_last',
					'label' => $field_label . ' - Last Name',
					'type' => 'name-last',
					'options' => [],
				];
				continue;
			}
			
			$options = [];
			if (!empty($field['choices'])) {
				foreach ($field['choices'] as $choice) {
					// WPForms often has empty 'value' strings, so we need to check for empty, not just null
					$choice_value = !empty($choice['value']) ? $choice['value'] : ($choice['label'] ?? '');
					$choice_label = !empty($choice['label']) ? $choice['label'] : ($choice['value'] ?? '');
					
					$options[] = [
						'value' => $choice_value,
						'label' => $choice_label,
					];
				}
			}

			$fields[] = [
				'id' => 'field_' . $field_id,
				'label' => $field_label,
				'type' => $field_type,
				'options' => $options,
			];
		}

		return $fields;
	}

	// ========== FORMINATOR ==========

	private function get_forminator_forms(): array {
		if (!class_exists('Forminator_API')) {
			return [];
		}

		$forms = \Forminator_API::get_forms(null, 1, -1);
		if (empty($forms)) {
			return [];
		}

		return array_map(fn($form) => [
			'id' => $form->id,
			'name' => $form->name ?? 'Form ' . $form->id,
		], $forms);
	}

	private function get_forminator_fields($form_id): array {
		if (!class_exists('Forminator_API')) {
			return [];
		}

		// Use Forminator's API to get fields - this returns Forminator_Form_Field_Model objects
		$form_fields = \Forminator_API::get_form_fields($form_id);
		if (is_wp_error($form_fields) || empty($form_fields)) {
			return [];
		}

		$fields = [];
		foreach ($form_fields as $field_model) {
			if (!is_object($field_model)) {
				continue;
			}

			// Convert field model to array for easier access
			$field = method_exists($field_model, 'to_array') ? $field_model->to_array() : (array) $field_model;
			
			$field_type = $field['type'] ?? '';
			$element_id = $field['element_id'] ?? $field['id'] ?? '';
			$field_label = $field['field_label'] ?? 'Field';
			
			// Skip non-mappable fields
			if (in_array($field_type, ['hidden', 'submit', 'captcha', 'section', 'page-break', 'html', 'consent'])) {
				continue;
			}

			// Handle name fields
			if ($field_type === 'name') {
				$fields[] = [
					'id' => $element_id . '-first-name',
					'label' => $field_label . ' - First Name',
					'type' => 'name-first',
					'options' => [],
				];
				$fields[] = [
					'id' => $element_id . '-last-name',
					'label' => $field_label . ' - Last Name',
					'type' => 'name-last',
					'options' => [],
				];
				continue;
			}
			
			// Handle address fields
			if ($field_type === 'address') {
				$address_parts = [
					'street_address' => 'Street Address',
					'address_line' => 'Address Line 2',
					'city' => 'City',
					'state' => 'State/Province',
					'zip' => 'ZIP/Postal Code',
					'country' => 'Country',
				];
				foreach ($address_parts as $part_key => $part_label) {
					$fields[] = [
						'id' => $element_id . '-' . $part_key,
						'label' => $field_label . ' - ' . $part_label,
						'type' => 'address-part',
						'options' => [],
					];
				}
				continue;
			}

			$options = [];
			if (!empty($field['options']) && is_array($field['options'])) {
				foreach ($field['options'] as $opt) {
					// Forminator options are arrays with 'label' and 'value' keys
					// Handle empty value strings - use label as fallback
					if (is_array($opt)) {
						$opt_value = !empty($opt['value']) ? $opt['value'] : ($opt['label'] ?? '');
						$opt_label = !empty($opt['label']) ? $opt['label'] : ($opt['value'] ?? '');
						
						$options[] = [
							'value' => $opt_value,
							'label' => $opt_label,
						];
					}
				}
			}

			$fields[] = [
				'id' => $element_id,
				'label' => $field_label,
				'type' => $field_type,
				'options' => $options,
			];
		}

		return $fields;
	}

	// ========== FLUENT FORMS ==========

	private function get_fluentforms_forms(): array {
		if (!defined('FLUENTFORM')) {
			return [];
		}

		global $wpdb;
		$table = $wpdb->prefix . 'fluentform_forms';
		
		$forms = $wpdb->get_results("SELECT id, title FROM {$table} WHERE status = 'published' ORDER BY title ASC");
		if (empty($forms)) {
			return [];
		}

		return array_map(fn($form) => [
			'id' => (int) $form->id,
			'name' => $form->title,
		], $forms);
	}

	private function get_fluentforms_fields($form_id): array {
		if (!defined('FLUENTFORM')) {
			return [];
		}

		global $wpdb;
		$table = $wpdb->prefix . 'fluentform_forms';
		
		$form = $wpdb->get_row($wpdb->prepare("SELECT form_fields FROM {$table} WHERE id = %d", $form_id));
		if (empty($form) || empty($form->form_fields)) {
			return [];
		}

		$form_fields = json_decode($form->form_fields, true);
		if (empty($form_fields['fields'])) {
			return [];
		}

		$fields = [];
		foreach ($form_fields['fields'] as $field) {
			$this->extract_fluentform_fields($field, $fields);
		}

		return $fields;
	}

	private function extract_fluentform_fields(array $field, array &$fields): void {
		// Handle container fields
		if (!empty($field['columns'])) {
			foreach ($field['columns'] as $column) {
				if (!empty($column['fields'])) {
					foreach ($column['fields'] as $inner_field) {
						$this->extract_fluentform_fields($inner_field, $fields);
					}
				}
			}
			return;
		}

		$element = $field['element'] ?? '';
		$name = $field['attributes']['name'] ?? '';
		$label = $field['settings']['label'] ?? '';
		
		// Create better label from field name if not set
		if (empty($label)) {
			$label = ucwords(str_replace(['_', '-'], ' ', $name));
		}

		if (empty($name)) {
			return;
		}
		
		// Skip non-mappable elements
		$excluded_elements = ['custom_html', 'section_break', 'form_step', 'recaptcha', 'hcaptcha', 'turnstile', 'action_hook'];
		if (in_array($element, $excluded_elements)) {
			return;
		}

		// Handle name fields
		if ($element === 'input_name') {
			$fields[] = [
				'id' => $name . '.first_name',
				'label' => $label . ' - First Name',
				'type' => 'name-first',
				'options' => [],
			];
			$fields[] = [
				'id' => $name . '.last_name',
				'label' => $label . ' - Last Name',
				'type' => 'name-last',
				'options' => [],
			];
			return;
		}
		
		// Handle address fields
		if ($element === 'address') {
			$address_parts = [
				'address_line_1' => 'Address Line 1',
				'address_line_2' => 'Address Line 2',
				'city' => 'City',
				'state' => 'State/Province',
				'zip' => 'ZIP/Postal Code',
				'country' => 'Country',
			];
			foreach ($address_parts as $part_key => $part_label) {
				$fields[] = [
					'id' => $name . '.' . $part_key,
					'label' => $label . ' - ' . $part_label,
					'type' => 'address-part',
					'options' => [],
				];
			}
			return;
		}

		$options = [];
		if (!empty($field['settings']['advanced_options'])) {
			foreach ($field['settings']['advanced_options'] as $opt) {
				// Handle empty value strings - use label as fallback
				$opt_value = !empty($opt['value']) ? $opt['value'] : ($opt['label'] ?? '');
				$opt_label = !empty($opt['label']) ? $opt['label'] : ($opt['value'] ?? '');
				
				$options[] = [
					'value' => $opt_value,
					'label' => $opt_label,
				];
			}
		}

		$fields[] = [
			'id' => $name,
			'label' => $label,
			'type' => $element,
			'options' => $options,
		];
	}

	/**
	 * Get CareHQ standard fields for mapping
	 */
	public function get_carehq_fields(): array {
		return SubmissionHandler::get_carehq_fields();
	}

	/**
	 * Clear the forms cache
	 */
	public function clear_cache(): void {
		$this->forms_cache = null;
	}
}
