<?php
defined( 'ABSPATH' ) || exit;

class Formulate_Pricing_Form {

	public static function create( $data ) {
		global $wpdb;
		$table  = Formulate_Pricing_Database::get_forms_table();
		$config = isset( $data['form_config'] ) ? $data['form_config'] : self::default_config();

		$inserted = $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
			$table,
			array(
				'title'       => sanitize_text_field( $data['title'] ?? 'New Form' ),
				'slug'        => sanitize_title( $data['title'] ?? 'new-form' ),
				'form_config' => wp_json_encode( $config ),
				'status'      => 'published',
				'created_at'  => current_time( 'mysql' ),
				'updated_at'  => current_time( 'mysql' ),
			)
		);

		return $inserted ? $wpdb->insert_id : false;
	}

	public static function update( $id, $data ) {
		global $wpdb;
		$table = Formulate_Pricing_Database::get_forms_table();

		$update_data = array(
			'updated_at' => current_time( 'mysql' ),
		);

		if ( isset( $data['title'] ) ) {
			$update_data['title'] = sanitize_text_field( $data['title'] );
			$update_data['slug']  = sanitize_title( $data['title'] );
		}

		if ( isset( $data['form_config'] ) ) {
			$config                    = is_array( $data['form_config'] ) ? $data['form_config'] : json_decode( wp_unslash( $data['form_config'] ), true );
			$update_data['form_config'] = wp_json_encode( $config );
		}

		if ( isset( $data['status'] ) ) {
			$update_data['status'] = sanitize_text_field( $data['status'] );
		}

		return $wpdb->update( $table, $update_data, array( 'id' => intval( $id ) ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
	}

	public static function get( $id ) {
		global $wpdb;
		$table = Formulate_Pricing_Database::get_forms_table();
		// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter
		$form  = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM `$table` WHERE id = %d", intval( $id ) ) );
		if ( $form ) {
			$form->form_config = json_decode( $form->form_config, true );
		}
		return $form;
	}

	public static function get_all( $args = array() ) {
		global $wpdb;
		$table = Formulate_Pricing_Database::get_forms_table();

		$defaults = array(
			'status'  => '',
			'per_page' => 20,
			'page'    => 1,
			'search'  => '',
			'orderby' => 'created_at',
			'order'   => 'DESC',
		);
		$args = wp_parse_args( $args, $defaults );

		$where  = '1=1';
		$values = array();

		if ( $args['status'] ) {
			$where   .= ' AND status = %s';
			$values[] = $args['status'];
		}

		if ( $args['search'] ) {
			$where   .= ' AND title LIKE %s';
			$values[] = '%' . $wpdb->esc_like( $args['search'] ) . '%';
		}

		$offset  = ( max( 1, intval( $args['page'] ) ) - 1 ) * intval( $args['per_page'] );
		$allowed_order = array( 'ASC', 'DESC' );
		$order   = in_array( strtoupper( $args['order'] ), $allowed_order, true ) ? strtoupper( $args['order'] ) : 'DESC';
		$allowed_orderby = array( 'id', 'title', 'created_at', 'updated_at', 'status' );
		$orderby = in_array( $args['orderby'], $allowed_orderby, true ) ? $args['orderby'] : 'created_at';

		$values[] = intval( $args['per_page'] );
		$values[] = $offset;

		// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber,PluginCheck.Security.DirectDB.UnescapedDBParameter,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
		$forms = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM `$table` WHERE $where ORDER BY $orderby $order LIMIT %d OFFSET %d", ...$values ) );
		foreach ( $forms as &$form ) {
			$form->form_config = json_decode( $form->form_config, true );
		}
		return $forms;
	}

	public static function count( $args = array() ) {
		global $wpdb;
		$table  = Formulate_Pricing_Database::get_forms_table();
		$where  = '1=1';
		$values = array();

		if ( ! empty( $args['status'] ) ) {
			$where   .= ' AND status = %s';
			$values[] = $args['status'];
		}

		if ( ! empty( $args['search'] ) ) {
			$where   .= ' AND title LIKE %s';
			$values[] = '%' . $wpdb->esc_like( $args['search'] ) . '%';
		}

		if ( $values ) {
			// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter
			return (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM `$table` WHERE $where", ...$values ) );
		}
		// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter
		return (int) $wpdb->get_var( "SELECT COUNT(*) FROM `$table` WHERE $where" );
	}

	public static function delete( $id ) {
		global $wpdb;
		$forms_table   = Formulate_Pricing_Database::get_forms_table();
		$entries_table = Formulate_Pricing_Database::get_entries_table();

		$wpdb->delete( $entries_table, array( 'form_id' => intval( $id ) ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
		return $wpdb->delete( $forms_table, array( 'id' => intval( $id ) ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
	}

	public static function duplicate( $id ) {
		$form = self::get( $id );
		if ( ! $form ) {
			return false;
		}
		return self::create(
			array(
				'title'       => $form->title . ' (Copy)',
				'form_config' => $form->form_config,
			)
		);
	}

	public static function default_config() {
		return array(
			'settings' => array(
				'submit_text'     => 'Submit',
				'next_text'       => 'Next',
				'prev_text'       => 'Previous',
				'success_message' => 'Thank you! Your submission has been received.',
				'redirect_url'    => '',
				'multi_step'      => false,
				'show_progress'   => true,
				'wc_enabled'      => false,
				'wc_product_id'   => 0,
			),
			'styling'  => array(
				'primary_color'         => '#2563eb',
				'bg_color'              => '#ffffff',
				'text_color'            => '#1f2937',
				'label_color'           => '#374151',
				'border_radius'         => '8',
				'font_size'             => '15',
				'input_bg'              => '#f9fafb',
				'input_border'          => '#d1d5db',
				'button_bg'             => '#2563eb',
				'button_text_color'     => '#ffffff',
				'button_border_radius'  => '8',
				'form_width'            => '100',
				'form_padding'          => '24',
				'field_gap'             => '16',
				'card_bg'               => '#f9fafb',
				'card_border'           => '#d1d5db',
				'card_selected_bg'      => '#eff6ff',
				'card_selected_border'  => '#2563eb',
			),
		'steps'         => array(
			array(
				'id'     => 'step_1',
				'title'  => 'Step 1',
				'fields' => array(),
			),
		),
		'notifications' => array(
			'admin_enabled'    => false,
			'admin_to'         => '',
			'admin_subject'    => 'New submission: {form_title}',
			'admin_reply_to'   => '',
			'user_enabled'     => false,
			'user_email_field' => '',
			'user_subject'     => 'Thank you for your submission',
			'user_message'     => 'Hi,\n\nWe have received your submission and will be in touch soon.\n\nThank you!',
		),
	);
}

	public static function get_all_fields( $form_config ) {
		$fields = array();
		if ( ! empty( $form_config['steps'] ) ) {
			foreach ( $form_config['steps'] as $step ) {
				if ( ! empty( $step['fields'] ) ) {
					foreach ( $step['fields'] as $field ) {
						$fields[] = $field;
					}
				}
			}
		}
		return $fields;
	}

	/**
	 * Field types that are layout-only (no submission / cart line).
	 *
	 * @return string[]
	 */
	public static function layout_field_types() {
		return array( 'heading', 'paragraph', 'divider', 'spacer', 'hidden' );
	}

	/**
	 * Normalize checkbox / multi-select POST values (single selection may arrive as a string).
	 *
	 * @param mixed $raw Raw POST value.
	 * @return string[]
	 */
	public static function normalize_multi_value( $raw ) {
		if ( is_array( $raw ) ) {
			return array_values(
				array_filter(
					array_map(
						static function ( $v ) {
							return sanitize_text_field( (string) $v );
						},
						$raw
					),
					'strlen'
				)
			);
		}
		if ( null === $raw || '' === $raw ) {
			return array();
		}
		return array( sanitize_text_field( (string) $raw ) );
	}

	/**
	 * Whether a submitted value matches an option (value or label).
	 *
	 * @param array  $option   Option config.
	 * @param string $selected Submitted value.
	 * @return bool
	 */
	public static function option_matches_selection( $option, $selected ) {
		if ( ! is_array( $option ) ) {
			return (string) $option === (string) $selected;
		}
		$opt_value = isset( $option['value'] ) && '' !== (string) $option['value']
			? (string) $option['value']
			: ( isset( $option['label'] ) ? (string) $option['label'] : '' );
		$opt_label = isset( $option['label'] ) ? (string) $option['label'] : $opt_value;
		$sel       = (string) $selected;
		return $sel === $opt_value || $sel === $opt_label;
	}

	/**
	 * Price for one selected option value.
	 *
	 * @param array  $field    Field config.
	 * @param string $selected Submitted option value.
	 * @return float
	 */
	public static function get_option_price_for_selection( $field, $selected ) {
		$options = isset( $field['options'] ) ? $field['options'] : array();
		foreach ( $options as $opt ) {
			if ( self::option_matches_selection( $opt, $selected ) ) {
				return floatval( is_array( $opt ) && isset( $opt['price'] ) ? $opt['price'] : 0 );
			}
		}
		return 0.0;
	}

	/**
	 * Calculate cart total from fields with priced options.
	 *
	 * @param array $form_config Form config.
	 * @param array $entry_data  Submitted entry data.
	 * @return float
	 */
	public static function calculate_priced_total( $form_config, $entry_data ) {
		$total      = 0.0;
		$all_fields = self::get_all_fields( $form_config );

		foreach ( $all_fields as $field ) {
			$total += self::get_field_price( $field, $entry_data );
		}

		return $total;
	}

	/**
	 * Price contributed by one field's selected option(s).
	 *
	 * @param array $field      Field config.
	 * @param array $entry_data Entry data.
	 * @return float
	 */
	public static function get_field_price( $field, $entry_data ) {
		$fid   = isset( $field['id'] ) ? $field['id'] : '';
		$type  = isset( $field['type'] ) ? $field['type'] : 'text';
		$raw   = isset( $entry_data[ $fid ] ) ? $entry_data[ $fid ] : null;
		$multi = in_array( $type, array( 'checkbox', 'card_choice' ), true )
			&& ( 'checkbox' === $type || ! empty( $field['multi_select'] ) );

		if ( null === $raw || '' === $raw || array() === $raw ) {
			return 0.0;
		}

		if ( $multi ) {
			$selections = self::normalize_multi_value( $raw );
			$total      = 0.0;
			foreach ( $selections as $selected ) {
				$total += self::get_option_price_for_selection( $field, $selected );
			}
			return $total;
		}

		$selected = is_array( $raw ) ? ( isset( $raw[0] ) ? $raw[0] : '' ) : $raw;
		return self::get_option_price_for_selection( $field, (string) $selected );
	}

	/**
	 * Human-readable value for cart / order display.
	 *
	 * @param array       $field      Field config.
	 * @param string|array $value     Raw value.
	 * @return string
	 */
	public static function format_field_display_value( $field, $value ) {
		$type         = isset( $field['type'] ) ? $field['type'] : 'text';
		$choice_types = array( 'checkbox', 'radio', 'select', 'card_choice' );

		if ( in_array( $type, $choice_types, true ) && ! empty( $field['options'] ) ) {
			$selections = is_array( $value ) ? self::normalize_multi_value( $value ) : self::normalize_multi_value( $value );
			$parts      = array();
			foreach ( $selections as $sel ) {
				$label = self::resolve_option_label( $field, $sel );
				$price = self::get_option_price_for_selection( $field, $sel );
				if ( $price > 0 && function_exists( 'formulate_pricing_format_price' ) ) {
					$parts[] = $label . ' (' . formulate_pricing_format_price( $price ) . ')';
				} else {
					$parts[] = $label;
				}
			}
			return implode( ', ', array_filter( $parts ) );
		}

		if ( is_array( $value ) ) {
			$labels = array();
			foreach ( $value as $v ) {
				$labels[] = self::resolve_option_label( $field, $v );
			}
			return implode( ', ', array_filter( $labels ) );
		}

		return self::resolve_option_label( $field, $value );
	}

	/**
	 * @param array  $field Field config.
	 * @param string $value Option value.
	 * @return string
	 */
	private static function resolve_option_label( $field, $value ) {
		$options = isset( $field['options'] ) ? $field['options'] : array();
		foreach ( $options as $opt ) {
			if ( self::option_matches_selection( $opt, (string) $value ) ) {
				if ( is_array( $opt ) && isset( $opt['label'] ) && '' !== (string) $opt['label'] ) {
					return (string) $opt['label'];
				}
				return isset( $opt['value'] ) ? (string) $opt['value'] : (string) $value;
			}
		}
		return (string) $value;
	}

	/**
	 * Lines for WooCommerce cart / checkout item data.
	 *
	 * @param int   $form_id    Form ID.
	 * @param array $entry_data Entry data.
	 * @return array<int, array{key: string, value: string}>
	 */
	public static function get_cart_display_items( $form_id, $entry_data ) {
		$form = self::get( $form_id );
		if ( ! $form || empty( $entry_data ) ) {
			return array();
		}

		$all_fields = self::get_all_fields( $form->form_config );
		$items      = array();

		foreach ( $all_fields as $field ) {
			$fid   = isset( $field['id'] ) ? $field['id'] : '';
			$type  = isset( $field['type'] ) ? $field['type'] : 'text';
			$value = isset( $entry_data[ $fid ] ) ? $entry_data[ $fid ] : null;

			if ( in_array( $type, self::layout_field_types(), true ) ) {
				continue;
			}
			if ( null === $value || '' === $value || array() === $value ) {
				continue;
			}

			$label = isset( $entry_data[ '_label_' . $fid ] ) ? $entry_data[ '_label_' . $fid ] : ( isset( $field['label'] ) ? $field['label'] : $fid );
			$text  = self::format_field_display_value( $field, $value );

			$items[] = array(
				'key'   => $label,
				'value' => $text,
			);
		}

		return $items;
	}
}
