<?php
/**
 * @license GPL-2.0-or-later
 * @link    https://wordpress.org/plugins/pressio-crm
 */
namespace PressioCRM\API;

defined( 'ABSPATH' ) || exit;

use PressioCRM\Framework\Controller;
use PressioCRM\Models\IntegrationModel;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

class RestIntegrations extends Controller {

	protected $rest_base = 'integrations';

	/** Mappable WPForms field types. */
	private const WPFORMS_MAPPABLE_TYPES = [
		'text', 'name', 'email', 'phone', 'address', 'hidden', 'number',
	];

	public function register_routes(): void {
		// ── Fluent Forms ───────────────────────────────────────────────────────

		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/fluent-forms',
			[
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => [ $this, 'get_fluent_forms' ],
				'permission_callback' => [ $this, 'require_settings_cap' ],
			]
		);

		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/fluent-forms/(?P<form_id>\d+)',
			[
				[
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => [ $this, 'get_form_mapping' ],
					'permission_callback' => [ $this, 'require_settings_cap' ],
					'args'                => [
						'form_id' => [
							'type'              => 'integer',
							'required'          => true,
							'sanitize_callback' => 'absint',
							'validate_callback' => 'rest_validate_request_arg',
						],
					],
				],
				[
					'methods'             => WP_REST_Server::EDITABLE,
					'callback'            => [ $this, 'save_form_mapping' ],
					'permission_callback' => [ $this, 'require_settings_cap' ],
					'args'                => $this->mapping_args( true ),
				],
			]
		);

		// ── WPForms ────────────────────────────────────────────────────────────

		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/wpforms',
			[
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => [ $this, 'get_wpforms' ],
				'permission_callback' => [ $this, 'require_settings_cap' ],
			]
		);

		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/wpforms/(?P<form_id>\d+)',
			[
				[
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => [ $this, 'get_wpforms_form_mapping' ],
					'permission_callback' => [ $this, 'require_settings_cap' ],
					'args'                => [
						'form_id' => [
							'type'              => 'integer',
							'required'          => true,
							'sanitize_callback' => 'absint',
							'validate_callback' => 'rest_validate_request_arg',
						],
					],
				],
				[
					'methods'             => WP_REST_Server::EDITABLE,
					'callback'            => [ $this, 'save_wpforms_mapping' ],
					'permission_callback' => [ $this, 'require_settings_cap' ],
					'args'                => $this->mapping_args( false ),
				],
			]
		);
	}

	// =========================================================================
	// Fluent Forms handlers
	// =========================================================================

	public function get_fluent_forms( WP_REST_Request $request ): WP_REST_Response {
		if ( ! $this->is_fluent_forms_active() ) {
			return $this->ok( [] );
		}

		$forms    = $this->fetch_ff_forms();
		$form_ids = array_column( $forms, 'id' );
		$mappings = $this->get_mappings_indexed( 'fluentforms', $form_ids );

		$result = [];
		foreach ( $forms as $form ) {
			$id      = (int) $form['id'];
			$mapping = $mappings[ $id ] ?? null;
			$config  = $this->decode_config( $mapping );

			$result[] = [
				'id'        => $id,
				'title'     => $form['title'],
				'is_active' => $mapping ? (bool) $mapping->is_active : false,
				'is_mapped' => ! empty( $config['email'] ),
				'config'    => $config,
			];
		}

		return $this->ok( $result );
	}

	public function get_form_mapping( WP_REST_Request $request ): WP_REST_Response {
		$form_id = absint( $request->get_param( 'form_id' ) );
		$record  = $this->find_mapping( 'fluentforms', $form_id );

		if ( ! $record ) {
			return $this->ok( [
				'form_id'   => $form_id,
				'is_active' => false,
				'config'    => (object) [],
			] );
		}

		$config = json_decode( $record->config ?? '{}', true );

		return $this->ok( [
			'form_id'   => $form_id,
			'is_active' => (bool) $record->is_active,
			'config'    => is_array( $config ) ? $config : (object) [],
		] );
	}

	public function save_form_mapping( WP_REST_Request $request ): WP_REST_Response {
		$form_id = absint( $request->get_param( 'form_id' ) );

		if ( ! $this->is_fluent_forms_active() ) {
			return $this->bad_request( 'ff_not_active', __( 'Fluent Forms is not installed or active.', 'pressio-crm' ) );
		}

		$form = $this->fetch_ff_form( $form_id );
		if ( ! $form ) {
			return $this->not_found();
		}

		$config    = $this->extract_mapping_config( $request );
		$is_active = $this->extract_is_active( $request );
		$existing  = $this->find_mapping( 'fluentforms', $form_id );

		if ( $existing ) {
			$existing->update( [
				'config'    => wp_json_encode( $config ),
				'is_active' => $is_active,
				'name'      => sanitize_text_field( $form['title'] ),
			] );
		} else {
			IntegrationModel::create( [
				'type'      => 'fluentforms',
				'object_id' => (string) $form_id,
				'name'      => sanitize_text_field( $form['title'] ),
				'config'    => wp_json_encode( $config ),
				'is_active' => $is_active,
			] );
		}

		return $this->ok( [
			'form_id'   => $form_id,
			'is_active' => (bool) $is_active,
			'config'    => $config,
		] );
	}

	// =========================================================================
	// WPForms handlers
	// =========================================================================

	public function get_wpforms( WP_REST_Request $request ): WP_REST_Response {
		if ( ! $this->is_wpforms_active() ) {
			return $this->ok( [] );
		}

		$posts    = $this->fetch_wpforms_posts();
		$form_ids = array_column( $posts, 'ID' );
		$mappings = $this->get_mappings_indexed( 'wpforms', $form_ids );

		$result = [];
		foreach ( $posts as $post ) {
			$id      = (int) $post->ID;
			$mapping = $mappings[ $id ] ?? null;
			$config  = $this->decode_config( $mapping );

			$result[] = [
				'id'        => $id,
				'title'     => sanitize_text_field( $post->post_title ),
				'is_active' => $mapping ? (bool) $mapping->is_active : false,
				'is_mapped' => ! empty( $config['email'] ),
				'config'    => $config,
			];
		}

		return $this->ok( $result );
	}

	public function get_wpforms_form_mapping( WP_REST_Request $request ): WP_REST_Response {
		$form_id = absint( $request->get_param( 'form_id' ) );

		if ( ! $this->is_wpforms_active() ) {
			return $this->bad_request( 'wpforms_not_active', __( 'WPForms is not installed or active.', 'pressio-crm' ) );
		}

		$post = get_post( $form_id );
		if ( ! $post || 'wpforms' !== $post->post_type ) {
			return $this->not_found();
		}

		$record = $this->find_mapping( 'wpforms', $form_id );
		$config = $this->decode_config( $record );
		$fields = $this->parse_wpforms_fields( $post->post_content );

		return $this->ok( [
			'form_id'   => $form_id,
			'is_active' => $record ? (bool) $record->is_active : false,
			'config'    => $config ?: (object) [],
			'fields'    => $fields,
		] );
	}

	public function save_wpforms_mapping( WP_REST_Request $request ): WP_REST_Response {
		$form_id = absint( $request->get_param( 'form_id' ) );

		if ( ! $this->is_wpforms_active() ) {
			return $this->bad_request( 'wpforms_not_active', __( 'WPForms is not installed or active.', 'pressio-crm' ) );
		}

		$post = get_post( $form_id );
		if ( ! $post || 'wpforms' !== $post->post_type ) {
			return $this->not_found();
		}

		$config    = $this->extract_mapping_config( $request );
		$is_active = $this->extract_is_active( $request );
		$existing  = $this->find_mapping( 'wpforms', $form_id );

		if ( $existing ) {
			$existing->update( [
				'config'    => wp_json_encode( $config ),
				'is_active' => $is_active,
				'name'      => sanitize_text_field( $post->post_title ),
			] );
		} else {
			IntegrationModel::create( [
				'type'      => 'wpforms',
				'object_id' => (string) $form_id,
				'name'      => sanitize_text_field( $post->post_title ),
				'config'    => wp_json_encode( $config ),
				'is_active' => $is_active,
			] );
		}

		return $this->ok( [
			'form_id'   => $form_id,
			'is_active' => (bool) $is_active,
			'config'    => $config,
		] );
	}

	// =========================================================================
	// Shared helpers
	// =========================================================================

	/** @return array<string, string> */
	private function extract_mapping_config( WP_REST_Request $request ): array {
		$config         = [];
		$allowed_fields = [ 'email', 'first_name', 'last_name', 'phone', 'company' ];

		foreach ( $allowed_fields as $field ) {
			$val = $request->get_param( $field );
			if ( null !== $val && '' !== $val ) {
				$config[ $field ] = sanitize_text_field( wp_unslash( (string) $val ) );
			}
		}

		return $config;
	}

	private function extract_is_active( WP_REST_Request $request ): int {
		$val = $request->get_param( 'is_active' );
		return null !== $val ? (int) rest_sanitize_boolean( $val ) : 0;
	}

	/** @return array<string, mixed> */
	private function decode_config( ?IntegrationModel $record ): array {
		if ( ! $record ) {
			return [];
		}
		$decoded = json_decode( $record->config ?? '{}', true );
		return is_array( $decoded ) ? $decoded : [];
	}

	/**
	 * Returns existing mappings for the given type + form IDs, keyed by form ID.
	 *
	 * @param int[] $form_ids
	 * @return array<int, IntegrationModel>
	 */
	private function get_mappings_indexed( string $type, array $form_ids ): array {
		if ( empty( $form_ids ) ) {
			return [];
		}

		$all     = IntegrationModel::query()->where( 'type', $type )->get();
		$indexed = [];
		foreach ( $all as $record ) {
			$indexed[ (int) $record->object_id ] = $record;
		}

		return $indexed;
	}

	private function find_mapping( string $type, int $form_id ): ?IntegrationModel {
		return IntegrationModel::query()
			->where( 'type', $type )
			->where( 'object_id', (string) $form_id )
			->first();
	}

	/**
	 * Shared args schema for all mapping save endpoints.
	 * $include_form_id — Fluent Forms encodes form_id in the URL, same for WPForms.
	 *
	 * @return array<string, array>
	 */
	private function mapping_args( bool $include_form_id ): array {
		$args = [
			'is_active'  => [
				'type'              => 'boolean',
				'required'          => false,
				'sanitize_callback' => 'rest_sanitize_boolean',
				'validate_callback' => 'rest_validate_request_arg',
			],
			'email'      => [
				'type'              => 'string',
				'required'          => false,
				'sanitize_callback' => 'sanitize_text_field',
				'validate_callback' => 'rest_validate_request_arg',
			],
			'first_name' => [
				'type'              => 'string',
				'required'          => false,
				'sanitize_callback' => 'sanitize_text_field',
				'validate_callback' => 'rest_validate_request_arg',
			],
			'last_name'  => [
				'type'              => 'string',
				'required'          => false,
				'sanitize_callback' => 'sanitize_text_field',
				'validate_callback' => 'rest_validate_request_arg',
			],
			'phone'      => [
				'type'              => 'string',
				'required'          => false,
				'sanitize_callback' => 'sanitize_text_field',
				'validate_callback' => 'rest_validate_request_arg',
			],
			'company'    => [
				'type'              => 'string',
				'required'          => false,
				'sanitize_callback' => 'sanitize_text_field',
				'validate_callback' => 'rest_validate_request_arg',
			],
		];

		if ( $include_form_id ) {
			$args['form_id'] = [
				'type'              => 'integer',
				'required'          => true,
				'sanitize_callback' => 'absint',
				'validate_callback' => 'rest_validate_request_arg',
			];
		}

		return $args;
	}

	// =========================================================================
	// Fluent Forms data helpers
	// =========================================================================

	private function is_fluent_forms_active(): bool {
		return defined( 'FLUENTFORM' );
	}

	/** @return array<int, array{id: int, title: string}> */
	private function fetch_ff_forms(): array {
		global $wpdb;

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$rows = $wpdb->get_results(
			$wpdb->prepare(
				'SELECT id, title FROM %i ORDER BY title ASC',
				$wpdb->prefix . 'fluentform_forms'
			),
			ARRAY_A
		);

		if ( ! $rows ) {
			return [];
		}

		return array_map(
			static fn( array $row ) => [
				'id'    => (int) $row['id'],
				'title' => sanitize_text_field( $row['title'] ),
			],
			$rows
		);
	}

	/** @return array{id: int, title: string}|null */
	private function fetch_ff_form( int $form_id ): ?array {
		global $wpdb;

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$row = $wpdb->get_row(
			$wpdb->prepare(
				'SELECT id, title FROM %i WHERE id = %d',
				$wpdb->prefix . 'fluentform_forms',
				$form_id
			),
			ARRAY_A
		);

		if ( ! $row ) {
			return null;
		}

		return [
			'id'    => (int) $row['id'],
			'title' => sanitize_text_field( $row['title'] ),
		];
	}

	// =========================================================================
	// WPForms data helpers
	// =========================================================================

	private function is_wpforms_active(): bool {
		return function_exists( 'wpforms' );
	}

	/** @return \WP_Post[] */
	private function fetch_wpforms_posts(): array {
		return get_posts( [
			'post_type'      => 'wpforms',
			'posts_per_page' => 200,
			'post_status'    => 'publish',
			'orderby'        => 'post_title',
			'order'          => 'ASC',
			'no_found_rows'  => true,
		] );
	}

	/**
	 * Parses a WPForms form's post_content (JSON) and returns a flat list of
	 * mappable fields — field types the user can assign to a CRM field.
	 *
	 * @return array<int, array{id: int, label: string, type: string}>
	 */
	private function parse_wpforms_fields( string $post_content ): array {
		if ( '' === $post_content ) {
			return [];
		}

		$data = json_decode( $post_content, true );
		if ( ! is_array( $data ) || empty( $data['fields'] ) || ! is_array( $data['fields'] ) ) {
			return [];
		}

		$result = [];
		foreach ( $data['fields'] as $field ) {
			$type = $field['type'] ?? '';
			if ( ! in_array( $type, self::WPFORMS_MAPPABLE_TYPES, true ) ) {
				continue;
			}

			$result[] = [
				'id'    => (int) ( $field['id'] ?? 0 ),
				'label' => sanitize_text_field( $field['label'] ?? '' ),
				'type'  => sanitize_key( $type ),
			];
		}

		return $result;
	}
}
