<?php
/**
 * Custom Fields ↔ CPT Builder bridge.
 *
 * @package CustomFields
 * @since 1.4.0
 */

namespace CustomFields;

use WP_PowerSuite\Core\NetworkScope;
use WP_PowerSuite\Core\OptionStoreModuleSettingsRepository;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Cross-module helpers for CPT Builder integration.
 */
final class CptBridge {

	public static function isCustomFieldsEnabled(): bool {
		return OptionStoreModuleSettingsRepository::isModuleEnabled( 'custom-fields' );
	}

	public static function isCptBuilderEnabled(): bool {
		return OptionStoreModuleSettingsRepository::isModuleEnabled( 'cpt-builder' );
	}

	/**
	 * Enabled field groups targeting a post type (relaxed matching).
	 *
	 * @return array<string, array<string, mixed>>
	 */
	public static function groupsForPostType( string $post_type ): array {
		if ( ! self::isCustomFieldsEnabled() || $post_type === '' ) {
			return [];
		}

		$locations = new Locations( new Storage() );

		return $locations->groupsForPost( 0, $post_type );
	}

	/**
	 * Admin URL to create a field group pre-filled for a post type.
	 */
	public static function createGroupUrl( string $post_type, string $title = '' ): string {
		$args = [
			'page'          => Admin::PAGE_SLUG,
			'action'        => 'add',
			'for_post_type' => sanitize_key( $post_type ),
		];

		if ( $title !== '' ) {
			$args['group_title'] = sanitize_text_field( $title );
		}

		return NetworkScope::adminUrl( 'admin.php', $args );
	}

	/**
	 * Admin URL to the Custom Fields list screen.
	 */
	public static function fieldsAdminUrl(): string {
		return NetworkScope::adminUrl( 'admin.php', [ 'page' => Admin::PAGE_SLUG ] );
	}

	/**
	 * Admin URL to create a taxonomy field group pre-filled for a taxonomy.
	 */
	public static function createTaxonomyGroupUrl( string $taxonomy, string $title = '' ): string {
		$args = [
			'page'         => Admin::PAGE_SLUG,
			'action'       => 'add',
			'for_taxonomy' => sanitize_key( $taxonomy ),
		];

		if ( $title !== '' ) {
			$args['group_title'] = sanitize_text_field( $title );
		}

		return NetworkScope::adminUrl( 'admin.php', $args );
	}

	/**
	 * Enabled field groups targeting a taxonomy (relaxed matching).
	 *
	 * @return array<string, array<string, mixed>>
	 */
	public static function groupsForTaxonomy( string $taxonomy ): array {
		if ( ! self::isCustomFieldsEnabled() || $taxonomy === '' ) {
			return [];
		}

		$locations = new Locations( new Storage() );

		return $locations->groupsForTaxonomy( $taxonomy, 0 );
	}

	/**
	 * Count enabled field groups for a post type.
	 */
	public static function countGroupsForPostType( string $post_type ): int {
		$counts = self::groupCountsByPostType();

		return $counts[ $post_type ] ?? 0;
	}

	/**
	 * Build a request-cached map of post type => enabled group count.
	 *
	 * Avoids N+1 lookups on the CPT Builder list table.
	 *
	 * @return array<string, int>
	 */
	public static function groupCountsByPostType(): array {
		static $counts = null;

		if ( is_array( $counts ) ) {
			return $counts;
		}

		$counts = [];
		if ( ! self::isCustomFieldsEnabled() ) {
			return $counts;
		}

		$storage = new Storage();
		foreach ( $storage->all() as $group ) {
			if ( ! is_array( $group ) || empty( $group['enabled'] ) ) {
				continue;
			}

			$rules = LocationRules::get( $group );
			if ( ( $rules['screen'] ?? 'post' ) !== 'post' ) {
				continue;
			}

			$matched = [];
			foreach ( (array) ( $rules['rules'] ?? [] ) as $rule ) {
				if ( ! is_array( $rule ) ) {
					continue;
				}
				if ( ( $rule['param'] ?? '' ) !== 'post_type' || ( $rule['operator'] ?? '' ) !== '==' ) {
					continue;
				}
				$post_type = sanitize_key( (string) ( $rule['value'] ?? '' ) );
				if ( $post_type !== '' ) {
					$matched[ $post_type ] = true;
				}
			}

			foreach ( array_keys( $matched ) as $post_type ) {
				$counts[ $post_type ] = ( $counts[ $post_type ] ?? 0 ) + 1;
			}
		}

		return $counts;
	}

	/**
	 * Resolve a friendly label for a post type key (registered or CPT Builder stored).
	 */
	private static function resolvePostTypeLabel( string $post_type ): string {
		if ( post_type_exists( $post_type ) ) {
			$object = get_post_type_object( $post_type );
			if ( $object instanceof \WP_Post_Type ) {
				return (string) $object->labels->singular_name;
			}
		}

		if ( class_exists( '\CptBuilder\Storage' ) ) {
			$stored = ( new \CptBuilder\Storage() )->get( $post_type );
			if ( is_array( $stored ) ) {
				$label = (string) ( $stored['labels']['singular_name'] ?? '' );
				if ( $label !== '' ) {
					return $label;
				}
			}
		}

		return $post_type;
	}

	/**
	 * Resolve a friendly label for a taxonomy key (registered or CPT Builder stored).
	 */
	private static function resolveTaxonomyLabel( string $taxonomy ): string {
		if ( taxonomy_exists( $taxonomy ) ) {
			$object = get_taxonomy( $taxonomy );
			if ( $object instanceof \WP_Taxonomy ) {
				return (string) $object->labels->singular_name;
			}
		}

		if ( class_exists( '\CptBuilder\TaxonomyStorage' ) ) {
			$stored = ( new \CptBuilder\TaxonomyStorage() )->get( $taxonomy );
			if ( is_array( $stored ) ) {
				$label = (string) ( $stored['labels']['singular_name'] ?? '' );
				if ( $label !== '' ) {
					return $label;
				}
			}
		}

		return $taxonomy;
	}

	/**
	 * Whether a post type key is known (registered or stored in CPT Builder).
	 */
	private static function isKnownPostType( string $post_type ): bool {
		if ( $post_type === '' ) {
			return false;
		}
		if ( post_type_exists( $post_type ) ) {
			return true;
		}

		return class_exists( '\CptBuilder\Storage' ) && ( new \CptBuilder\Storage() )->exists( $post_type );
	}

	/**
	 * Whether a taxonomy key is known (registered or stored in CPT Builder).
	 */
	private static function isKnownTaxonomy( string $taxonomy ): bool {
		if ( $taxonomy === '' ) {
			return false;
		}
		if ( taxonomy_exists( $taxonomy ) ) {
			return true;
		}

		return class_exists( '\CptBuilder\TaxonomyStorage' ) && ( new \CptBuilder\TaxonomyStorage() )->exists( $taxonomy );
	}

	/**
	 * Apply CPT prefill values to a new group definition.
	 *
	 * @param array<string, mixed> $definition Group definition.
	 * @return array<string, mixed>
	 */
	public static function applyPrefill( array $definition ): array {
		$post_type = isset( $_GET['for_post_type'] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only prefill.
			? sanitize_key( wp_unslash( (string) $_GET['for_post_type'] ) )
			: '';
		$taxonomy  = isset( $_GET['for_taxonomy'] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			? sanitize_key( wp_unslash( (string) $_GET['for_taxonomy'] ) )
			: '';
		$title     = isset( $_GET['group_title'] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			? sanitize_text_field( wp_unslash( (string) $_GET['group_title'] ) )
			: '';

		if ( $post_type !== '' && self::isKnownPostType( $post_type ) ) {
			$label = self::resolvePostTypeLabel( $post_type );

			if ( (string) ( $definition['title'] ?? '' ) === '' ) {
				$definition['title'] = $title !== '' ? $title : sprintf(
					/* translators: %s: post type singular label. */
					__( '%s Fields', 'wp-powersuite' ),
					$label
				);
			}

			$definition['location_rules'] = [
				'screen' => 'post',
				'match'  => 'all',
				'rules'  => [
					[
						'param'    => 'post_type',
						'operator' => '==',
						'value'    => $post_type,
					],
				],
			];
		} elseif ( $taxonomy !== '' && self::isKnownTaxonomy( $taxonomy ) ) {
			$label = self::resolveTaxonomyLabel( $taxonomy );

			if ( (string) ( $definition['title'] ?? '' ) === '' ) {
				$definition['title'] = $title !== '' ? $title : sprintf(
					/* translators: %s: taxonomy singular label. */
					__( '%s Term Fields', 'wp-powersuite' ),
					$label
				);
			}

			$definition['location_rules'] = [
				'screen' => 'taxonomy',
				'match'  => 'all',
				'rules'  => [
					[
						'param'    => 'taxonomy',
						'operator' => '==',
						'value'    => $taxonomy,
					],
				],
			];
		}

		return $definition;
	}

	/**
	 * Create a starter field group for a newly registered post type.
	 *
	 * @return string|null Created group key, or null when skipped.
	 */
	public static function createDefaultFieldGroup( string $post_type, string $singular_label ): ?string {
		if ( ! self::isCustomFieldsEnabled() || $post_type === '' ) {
			return null;
		}

		if ( self::groupsForPostType( $post_type ) !== [] ) {
			return null;
		}

		$storage   = new Storage();
		$validator = new Validator( $storage );
		$group_key = self::defaultGroupKey( $post_type, $storage );

		if ( $group_key === '' || $storage->exists( $group_key ) ) {
			return null;
		}

		$field                 = Config::defaultField();
		$field['key']          = 'field_summary';
		$field['label']        = __( 'Summary', 'wp-powersuite' );
		$field['name']         = 'summary';
		$field['type']         = 'textarea';
		$field['instructions'] = __( 'A short summary for this item.', 'wp-powersuite' );
		$field['rows']         = 4;

		$definition = Config::defaultGroup();
		$definition['key']            = $group_key;
		$definition['title']          = sprintf(
			/* translators: %s: post type singular label. */
			__( '%s Details', 'wp-powersuite' ),
			$singular_label !== '' ? $singular_label : $post_type
		);
		$definition['enabled']        = true;
		$definition['position']       = 'side';
		$definition['location_rules'] = [
			'screen' => 'post',
			'match'  => 'all',
			'rules'  => [
				[
					'param'    => 'post_type',
					'operator' => '==',
					'value'    => $post_type,
				],
			],
		];
		$definition['fields']         = [ $field ];
		$definition['created_at']     = time();
		$definition['updated_at']     = time();

		$errors = $validator->validateDefinition( $definition, false );
		if ( $errors !== [] ) {
			return null;
		}

		$storage->save( $group_key, $definition );

		return $group_key;
	}

	/**
	 * Create a starter field group for a newly registered taxonomy.
	 *
	 * @return string|null Created group key, or null when skipped.
	 */
	public static function createDefaultTaxonomyFieldGroup( string $taxonomy, string $singular_label ): ?string {
		if ( ! self::isCustomFieldsEnabled() || $taxonomy === '' ) {
			return null;
		}

		if ( self::groupsForTaxonomy( $taxonomy ) !== [] ) {
			return null;
		}

		$storage   = new Storage();
		$validator = new Validator( $storage );
		$group_key = self::defaultTaxonomyGroupKey( $taxonomy, $storage );

		if ( $group_key === '' || $storage->exists( $group_key ) ) {
			return null;
		}

		$field                 = Config::defaultField();
		$field['key']          = 'field_description';
		$field['label']        = __( 'Description', 'wp-powersuite' );
		$field['name']         = 'description';
		$field['type']         = 'textarea';
		$field['instructions'] = __( 'Extra details for this term.', 'wp-powersuite' );
		$field['rows']         = 4;

		$definition = Config::defaultGroup();
		$definition['key']            = $group_key;
		$definition['title']          = sprintf(
			/* translators: %s: taxonomy singular label. */
			__( '%s Term Fields', 'wp-powersuite' ),
			$singular_label !== '' ? $singular_label : $taxonomy
		);
		$definition['enabled']        = true;
		$definition['location_rules'] = [
			'screen' => 'taxonomy',
			'match'  => 'all',
			'rules'  => [
				[
					'param'    => 'taxonomy',
					'operator' => '==',
					'value'    => $taxonomy,
				],
			],
		];
		$definition['fields']         = [ $field ];
		$definition['created_at']     = time();
		$definition['updated_at']     = time();

		$errors = $validator->validateDefinition( $definition, false );
		if ( $errors !== [] ) {
			return null;
		}

		$storage->save( $group_key, $definition );

		return $group_key;
	}

	/**
	 * Resolve a unique default group key for a taxonomy.
	 */
	private static function defaultTaxonomyGroupKey( string $taxonomy, Storage $storage ): string {
		$candidates = [
			$taxonomy . '_term_fields',
			substr( $taxonomy, 0, 48 ) . '_terms',
		];

		foreach ( $candidates as $candidate ) {
			$candidate = substr( sanitize_key( $candidate ), 0, Config::MAX_KEY_LENGTH );
			if ( $candidate !== '' && preg_match( '/^[a-z][a-z0-9_]*$/', $candidate ) && ! $storage->exists( $candidate ) ) {
				return $candidate;
			}
		}

		for ( $i = 2; $i <= 99; $i++ ) {
			$candidate = substr( $taxonomy, 0, Config::MAX_KEY_LENGTH - strlen( (string) $i ) - 1 ) . '_' . $i;
			if ( ! $storage->exists( $candidate ) ) {
				return $candidate;
			}
		}

		return '';
	}

	/**
	 * Resolve a unique default group key for a post type.
	 */
	private static function defaultGroupKey( string $post_type, Storage $storage ): string {
		$candidates = [
			$post_type . '_details',
			substr( $post_type, 0, 50 ) . '_fields',
		];

		foreach ( $candidates as $candidate ) {
			$candidate = substr( sanitize_key( $candidate ), 0, Config::MAX_KEY_LENGTH );
			if ( $candidate !== '' && preg_match( '/^[a-z][a-z0-9_]*$/', $candidate ) && ! $storage->exists( $candidate ) ) {
				return $candidate;
			}
		}

		for ( $i = 2; $i <= 99; $i++ ) {
			$candidate = substr( $post_type, 0, Config::MAX_KEY_LENGTH - strlen( (string) $i ) - 1 ) . '_' . $i;
			if ( ! $storage->exists( $candidate ) ) {
				return $candidate;
			}
		}

		return '';
	}
}
