<?php
/**
 * KooKoa Folders — Localized JS data + builder modal payload.
 *
 * Builds the kookoawpfData object for wp_localize_script (settings flags,
 * Smart Startup Folder resolution, dynamic-rule options and the full
 * translatable string table) plus the colour/icon JSON consumed by the media
 * modal dialogs. Instantiated lazily and dispatched from KookoaWPF, which
 * keeps the hook registrations (so external references never change).
 *
 * @package KookoaWPF
 * @license GPL-2.0-or-later
 */

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

/**
 * Provides the localized JS payload, translatable strings and builder modal JSON.
 */
class KookoaWPF_Localize {

	/**
	 * Singleton instance.
	 *
	 * @var self|null
	 */
	private static $instance = null;

	/**
	 * Return the singleton instance.
	 *
	 * @return self
	 */
	public static function instance(): self {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Constructor. Hook registration lives on KookoaWPF (init_hooks), so this
	 * collaborator registers nothing of its own.
	 */
	private function __construct() {
		// Registration is owned by KookoaWPF (the hook surface).
	}

	/**
	 * Build the kookoawpfData array for wp_localize_script.
	 *
	 * @param string $post_type      The current post type (e.g. 'attachment').
	 * @param bool   $is_builder     Whether we are in a page builder editor.
	 * @return array<string, mixed>
	 */
	public function get_localize_data( $post_type = '', $is_builder = false ) {
		$pt   = $post_type;
		$data = array(
			'ajaxUrl'             => admin_url( 'admin-ajax.php' ),
			'nonce'               => wp_create_nonce( 'kookoawpf_nonce' ),
			'uploadNonce'         => wp_create_nonce( 'media-form' ),
			'postType'            => $pt,
			'showCount'           => get_option( 'kookoawpf_show_item_count', 'yes' ) === 'yes',
			'showBreadcrumb'      => get_option( 'kookoawpf_show_breadcrumb', 'yes' ) === 'yes',
			'breadcrumbStyle'     => get_option( 'kookoawpf_breadcrumb_style', 'default' ),
			'showSubfolderCards'  => $is_builder ? false : ( get_option( 'kookoawpf_show_subfolder_cards', 'yes' ) === 'yes' ),
			'showMetadataTooltip' => $is_builder ? false : ( get_option( 'kookoawpf_show_metadata_tooltip', 'yes' ) === 'yes' ),
			'showExif'            => $is_builder ? false : ( get_option( 'kookoawpf_show_exif', 'no' ) === 'yes' ),
			'sidebarWidth'        => kookoawpf_get_sidebar_width(),
			'treeFontSize'        => kookoawpf()->get_tree_font_size_css(),
			'isBuilderEditor'     => $is_builder,
			'strings'             => $this->get_localized_strings(),
			'defaultColor'        => get_option( 'kookoawpf_folder_color', '#39FF14' ),
			'ctxDisabled'         => get_option( 'kookoawpf_ctx_disabled', array() ),
			'customColors'        => get_option( 'kookoawpf_custom_colors', array() ),
			'shortcutsEnabled'    => 'yes' === get_option( 'kookoawpf_shortcuts_enabled', 'yes' ),
			// Always on in FREE — extensions that hook the settings row
			// can persist their own override via kookoawpf_save_settings
			// and would also override the localized value with their
			// own filter if needed. Hard-coding here heals any install
			// whose DB still carries the legacy 'no' from older saves.
			'showFolderStats'     => true,
			'upgradeUrl'          => admin_url( 'admin.php?page=kookoa-folders-upgrade' ),
			// Phase-aware CTA wording in the sidebar footer (sidebar-ui.js).
			// FALSE = fase 1 (never tried trial) → soft "TRY PRO FREE".
			// TRUE  = fase 3 (trial consumed)   → hard "Upgrade to PRO".
			'trialUsed'           => (bool) get_option( 'kookoawpf_trial_used' ),
			// FASE 4 marker — paid license ever activated on this site.
			// Set here in FREE so the flag survives PRO uninstall (when
			// PRO's own inject_localize_data filter no longer runs). PRO
			// overrides this with the same value when active.
			'paidCustomerEver'    => (bool) get_option( 'kookoawpf_paid_license_activated' ),
			'startupMode'         => $this->resolve_startup_mode(),
			'startupFolderId'     => $pt ? $this->resolve_startup_folder_id( $pt ) : 0,
			'startupFolderIds'    => $this->resolve_all_startup_folder_ids(),
			'dynamicFields'       => $pt ? KookoaWPF_Dynamic::get_rule_fields( $pt ) : array(),
			'dynamicOptions'      => ( $pt && ! $is_builder ) ? $this->build_dynamic_options( $pt ) : array(),
		);

		/**
		 * Extension point: companion plugins can inject additional keys into
		 * the localized kookoawpfData object without having to re-enqueue or
		 * re-localize.
		 *
		 * @param array<string, mixed>  $data       The localize data array.
		 * @param string $post_type  Current post type slug.
		 * @param bool   $is_builder Whether we are inside a visual builder editor.
		 */
		$data = apply_filters( 'kookoawpf_localize_data', $data, $post_type, $is_builder );

		return $data;
	}

	/**
	 * Return the current user's Smart Startup Folder mode.
	 *
	 * @return string One of: 'all', 'last', 'specific'.
	 */
	private function resolve_startup_mode() {
		$user_id = get_current_user_id();
		if ( ! $user_id ) {
			return 'all';
		}
		$mode = get_user_meta( $user_id, 'kookoawpf_startup_mode', true );
		if ( ! in_array( $mode, array( 'all', 'last', 'specific' ), true ) ) {
			return 'all';
		}
		return $mode;
	}

	/**
	 * Resolve the Smart Startup Folder id for a given post type.
	 * Returns 0 when the mode is "All Files" or when the saved folder no longer exists.
	 *
	 * @param string $post_type Post type slug.
	 * @return int Folder (term) id or 0.
	 */
	private function resolve_startup_folder_id( $post_type ) {
		$user_id = get_current_user_id();
		if ( ! $user_id ) {
			return 0;
		}
		$mode = $this->resolve_startup_mode();
		if ( 'all' === $mode ) {
			return 0;
		}
		$fid = 0;
		if ( 'last' === $mode ) {
			$fid = (int) get_user_meta( $user_id, 'kookoawpf_last_folder_' . $post_type, true );
		} elseif ( 'specific' === $mode ) {
			$ids = get_user_meta( $user_id, 'kookoawpf_startup_folder_ids', true );
			if ( is_array( $ids ) && isset( $ids[ $post_type ] ) ) {
				$fid = (int) $ids[ $post_type ];
			}
		}
		if ( $fid <= 0 ) {
			return 0;
		}
		// Validate the term still exists in the right taxonomy. Falls back to All Files otherwise.
		$taxonomy = KookoaWPF_Folders::get_taxonomy( $post_type );
		$term     = get_term( $fid, $taxonomy );
		if ( ! $term || is_wp_error( $term ) ) {
			return 0;
		}
		return $fid;
	}

	/**
	 * Resolve the startup folder id for every enabled post type.
	 * Used by the media modal (which always runs on 'attachment') even when the
	 * main screen localize data was computed for a different post type.
	 *
	 * @return array<string, mixed> Map of post_type => folder_id (0 for "All Files").
	 */
	private function resolve_all_startup_folder_ids() {
		$out = array();
		foreach ( kookoawpf()->get_supported_post_types() as $pt_slug ) {
			$out[ $pt_slug ] = $this->resolve_startup_folder_id( $pt_slug );
		}
		return $out;
	}

	/**
	 * Build the dropdown options payload that the Smart Folder rule builder
	 * (dynamic.js) consumes to populate select fields. Skipped on builder
	 * pages because the rule editor is unreachable there.
	 *
	 * @param string $post_type Post type slug.
	 * @return array<string, mixed> Options keyed by field name.
	 */
	private function build_dynamic_options( $post_type ) {
		$fields  = KookoaWPF_Dynamic::get_rule_fields( $post_type );
		$options = array();
		foreach ( $fields as $key => $field ) {
			if ( isset( $field['type'] ) && 'select' === $field['type'] ) {
				$options[ $key ] = KookoaWPF_Dynamic::get_field_options( $key );
			}
		}
		return $options;
	}

	/**
	 * Return all translatable strings for wp_localize_script.
	 *
	 * @return array<string, mixed>
	 */
	private function get_localized_strings() {
		return array(
			'newFolder'                 => __( 'New Folder', 'kookoa-folders' ),
			'createFirstFolder'         => __( 'Create your first folder!', 'kookoa-folders' ),
			'rename'                    => __( 'Rename', 'kookoa-folders' ),
			'delete'                    => __( 'Delete', 'kookoa-folders' ),
			'allItems'                  => __( 'All Items', 'kookoa-folders' ),
			'uncategorized'             => __( 'Uncategorized', 'kookoa-folders' ),
			'moveTo'                    => __( 'Moved to folder.', 'kookoa-folders' ),
			'errorGeneric'              => __( 'An error occurred.', 'kookoa-folders' ),
			'bulkOrganize'              => __( 'Bulk Organize', 'kookoa-folders' ),
			'selectFolder'              => __( 'Select a folder...', 'kookoa-folders' ),
			'itemsMoved'                => __( 'Items moved.', 'kookoa-folders' ),
			'noItemsSelected'           => __( 'No items selected.', 'kookoa-folders' ),
			'downloadZip'               => __( 'Download ZIP', 'kookoa-folders' ),
			'downloadSelected'          => __( 'Download', 'kookoa-folders' ),
			'duplicateFolder'           => __( 'Duplicate', 'kookoa-folders' ),
			'copyFolder'                => __( 'Copy', 'kookoa-folders' ),
			'cutFolder'                 => __( 'Cut', 'kookoa-folders' ),
			'pasteFolder'               => __( 'Paste', 'kookoa-folders' ),
			'lockFolder'                => __( 'Lock Folder', 'kookoa-folders' ),
			'unlockFolder'              => __( 'Unlock Folder', 'kookoa-folders' ),
			'pinFolder'                 => __( 'Pin to Top', 'kookoa-folders' ),
			'unpinFolder'               => __( 'Unpin', 'kookoa-folders' ),
			'newSubfolder'              => __( 'New Subfolder', 'kookoa-folders' ),
			'iconColor'                 => __( 'Folder Color', 'kookoa-folders' ),
			'selectAll'                 => __( 'Select All', 'kookoa-folders' ),
			'deselectAll'               => __( 'Deselect All', 'kookoa-folders' ),
			'cancelBulk'                => __( 'Cancel', 'kookoa-folders' ),
			'moveSelected'              => __( 'Move to:', 'kookoa-folders' ),
			'removeFromFolder'          => __( 'Removed from folder.', 'kookoa-folders' ),
			'folderLimitMsg'            => __( 'Folder limit reached.', 'kookoa-folders' ),
			'exportSuccess'             => __( 'Folders exported successfully.', 'kookoa-folders' ),
			'importSuccess'             => __( 'Import complete.', 'kookoa-folders' ),
			'invalidFile'               => __( 'Invalid file. Please select a .json file.', 'kookoa-folders' ),
			'settingsSaved'             => __( 'Saved!', 'kookoa-folders' ),
			'saveSettings'              => __( 'Save Settings', 'kookoa-folders' ),
			'exporting'                 => __( 'Exporting...', 'kookoa-folders' ),
			'exportAllFolders'          => __( 'Export All Folders (JSON)', 'kookoa-folders' ),
			'exportFailed'              => __( 'Export failed.', 'kookoa-folders' ),
			'importing'                 => __( 'Importing...', 'kookoa-folders' ),
			'importFolders'             => __( 'Import Folders', 'kookoa-folders' ),
			'importFailed'              => __( 'Import failed.', 'kookoa-folders' ),
			'importPreviewExported'     => __( 'Exported:', 'kookoa-folders' ),
			'importPreviewFrom'         => __( 'From:', 'kookoa-folders' ),
			/* translators: %s: plugin version number from the import file */
			'importPreviewVersion'      => __( 'Plugin v%s', 'kookoa-folders' ),
			'importReplaceConfirm'      => __( '⚠️ This will DELETE all existing folders before importing. Continue?', 'kookoa-folders' ),
			'importModeReplaceDesc'     => __( 'Deletes all existing folders before importing.', 'kookoa-folders' ),
			'importModeMergeDesc'       => __( 'Keeps current folders and adds imported ones.', 'kookoa-folders' ),
			'importButtonIdle'          => __( 'Import', 'kookoa-folders' ),
			'uploadNoValidFiles'        => __( 'No valid files found in the selected folder.', 'kookoa-folders' ),
			'uploadNoFilesOrFolders'    => __( 'No files or folders found.', 'kookoa-folders' ),
			/* translators: 1: number of folders to upload, 2: number of files to upload */
			'uploadStarting'            => __( 'Starting upload... %1$s folders, %2$s files', 'kookoa-folders' ),
			/* translators: 1: current folder index, 2: total folders, 3: folder name being created */
			'uploadCreatingFolders'     => __( 'Creating folders (%1$s/%2$s) — %3$s', 'kookoa-folders' ),
			/* translators: 1: current file index, 2: total files, 3: file name being uploaded */
			'uploadingFiles'            => __( 'Uploading files (%1$s/%2$s) — %3$s', 'kookoa-folders' ),
			/* translators: 1: number of folders created, 2: number of files uploaded */
			'uploadDone'                => __( 'Done! %1$s folders created, %2$s files uploaded.', 'kookoa-folders' ),
			'removeColor'               => __( 'Remove', 'kookoa-folders' ),
			'sorted'                    => __( 'Folders sorted.', 'kookoa-folders' ),
			'moveFolder'                => __( 'Move Folder', 'kookoa-folders' ),
			'moveToTop'                 => __( 'Move to Top', 'kookoa-folders' ),
			'moveUp'                    => __( 'Move Up', 'kookoa-folders' ),
			'moveDown'                  => __( 'Move Down', 'kookoa-folders' ),
			'moveToBottom'              => __( 'Move to Bottom', 'kookoa-folders' ),
			'changeIcon'                => __( 'Change Icon', 'kookoa-folders' ),
			'deletePermanently'         => __( 'Delete permanently', 'kookoa-folders' ),
			'confirmDeleteItems'        => __( 'Delete selected items permanently? This cannot be undone.', 'kookoa-folders' ),
			'itemsDeleted'              => __( 'Items deleted.', 'kookoa-folders' ),
			'folderBulkPin'             => __( 'Pinned to top.', 'kookoa-folders' ),
			'folderBulkLock'            => __( 'Folders locked.', 'kookoa-folders' ),
			'folderBulkDeleted'         => __( 'Folders deleted.', 'kookoa-folders' ),
			/* translators: %d: number of folders that were duplicated */
			'folderBulkDuplicated'      => __( '%d folders duplicated.', 'kookoa-folders' ),
			'moveToFolder'              => __( 'Move to Folder...', 'kookoa-folders' ),
			'folderMoved'               => __( 'Folder moved.', 'kookoa-folders' ),
			'bulkProcessing'            => __( 'Processing...', 'kookoa-folders' ),
			'folderAlreadyHere'         => __( 'Folder is already in this location.', 'kookoa-folders' ),
			'folderDeleted'             => __( 'Folder deleted.', 'kookoa-folders' ),
			'deleteTitle'               => __( 'Delete Folder', 'kookoa-folders' ),
			'deleteMsg'                 => __( 'Are you sure you want to delete this folder? All subfolders will also be deleted. The items inside will NOT be deleted.', 'kookoa-folders' ),
			'deleteBulkTitle'           => __( 'Delete Folders', 'kookoa-folders' ),
			'deleteBulkMsg'             => __( 'Are you sure you want to delete the selected folders? All subfolders will also be deleted. The items inside will NOT be deleted.', 'kookoa-folders' ),
			'folderRenamed'             => __( 'Folder renamed.', 'kookoa-folders' ),
			'folderCreated'             => __( 'Folder created.', 'kookoa-folders' ),
			'folderDuplicated'          => __( 'Folder duplicated.', 'kookoa-folders' ),
			'folderLockedDelete'        => __( 'Contains a locked subfolder.', 'kookoa-folders' ),
			'lockedSubfolderPresent'    => __( 'Contains a locked subfolder', 'kookoa-folders' ),
			'folderLockedSelf'          => __( 'This folder is locked.', 'kookoa-folders' ),
			'colorUpdated'              => __( 'Color updated.', 'kookoa-folders' ),
			'colorReset'                => __( 'Color reset.', 'kookoa-folders' ),
			'resetColor'                => __( 'Reset color', 'kookoa-folders' ),
			'resetToDefault'            => __( 'Reset to Default', 'kookoa-folders' ),
			'iconUpdated'               => __( 'Icon updated.', 'kookoa-folders' ),
			'iconReset'                 => __( 'Icon reset.', 'kookoa-folders' ),
			'invalidHexColor'           => __( 'Invalid hex color. Use format #FF0000.', 'kookoa-folders' ),
			'breadcrumbLabel'           => __( 'Folder navigation', 'kookoa-folders' ),
			'hasSubfolders'             => __( 'Has subfolders', 'kookoa-folders' ),
			'bulkSelect'                => __( 'Bulk Select', 'kookoa-folders' ),
			'exitSelection'             => __( 'Exit Selection', 'kookoa-folders' ),
			'expandAll'                 => __( 'Expand All', 'kookoa-folders' ),
			'collapseAll'               => __( 'Collapse All', 'kookoa-folders' ),
			'displayFolderId'           => __( 'Display Folder ID', 'kookoa-folders' ),
			'hideFolderId'              => __( 'Hide Folder ID', 'kookoa-folders' ),

			// Keyboard shortcuts modal.
			'keyboardShortcuts'         => __( 'Keyboard Shortcuts', 'kookoa-folders' ),
			'shortcutCreateFolder'      => __( 'Create New Folder', 'kookoa-folders' ),
			'shortcutNewSubfolder'      => __( 'Create Subfolder', 'kookoa-folders' ),
			'shortcutRenameFolder'      => __( 'Rename Folder', 'kookoa-folders' ),
			'shortcutMoveToFolder'      => __( 'Move to Folder', 'kookoa-folders' ),
			'shortcutCopyFolder'        => __( 'Copy Folder', 'kookoa-folders' ),
			'shortcutCutFolder'         => __( 'Cut Folder', 'kookoa-folders' ),
			'shortcutPasteFolder'       => __( 'Paste Folder', 'kookoa-folders' ),
			'shortcutDuplicate'         => __( 'Duplicate Folder', 'kookoa-folders' ),
			'shortcutChangeColor'       => __( 'Change Color', 'kookoa-folders' ),
			'shortcutPinUnpin'          => __( 'Pin / Unpin', 'kookoa-folders' ),
			'shortcutLockUnlock'        => __( 'Lock / Unlock', 'kookoa-folders' ),
			'shortcutNavigate'          => __( 'Navigate Folders', 'kookoa-folders' ),
			'shortcutExpandCollapse'    => __( 'Expand / Collapse', 'kookoa-folders' ),
			'shortcutReorderFolder'     => __( 'Reorder Folder', 'kookoa-folders' ),
			'shortcutCloseModal'        => __( 'Close Modal', 'kookoa-folders' ),
			'shortcutConfirmAction'     => __( 'Confirm Action', 'kookoa-folders' ),

			// Smart Folders.
			'newDynamic'                => __( 'New', 'kookoa-folders' ) . '⚡' . __( 'Smart Folder', 'kookoa-folders' ),
			'editRules'                 => __( 'Edit Rules', 'kookoa-folders' ),
			'editRulesTitle'            => __( 'Edit', 'kookoa-folders' ) . '⚡' . __( 'Rules', 'kookoa-folders' ),
			'dynamicFolder'             => __( 'Smart Folder', 'kookoa-folders' ),
			'addRule'                   => __( 'Add Rule', 'kookoa-folders' ),
			'saveRules'                 => __( 'Save', 'kookoa-folders' ),
			'rulesSaved'                => __( '⚡ Smart folder updated.', 'kookoa-folders' ),
			'noRules'                   => __( 'Add at least one rule.', 'kookoa-folders' ),
			'selectField'               => __( 'Select field...', 'kookoa-folders' ),
			'actionNotAllowedSmart'     => __( '⚡ Action not allowed on smart folder.', 'kookoa-folders' ),
			'smartAutoPopulated'        => __( '⚡ Smart folders are auto-populated.', 'kookoa-folders' ),
			'smartFolderMoved'          => __( '⚡ Smart folder moved.', 'kookoa-folders' ),
			'smartFolderCreated'        => __( '⚡ Smart folder created.', 'kookoa-folders' ),
			'smartFolderRenamed'        => __( '⚡ Smart folder renamed.', 'kookoa-folders' ),
			'smartFolderDeleted'        => __( '⚡ Smart folder deleted.', 'kookoa-folders' ),
			'smartFolderLocked'         => __( '⚡ Smart folder locked.', 'kookoa-folders' ),
			'smartFolderUnlocked'       => __( '⚡ Smart folder unlocked.', 'kookoa-folders' ),
			'smartPinnedToTop'          => __( '⚡ Pinned to top.', 'kookoa-folders' ),
			'smartUnpinned'             => __( '⚡ Unpinned.', 'kookoa-folders' ),
			'smartBulkPinPlural'        => __( '⚡ Pinned to top.', 'kookoa-folders' ),
			'smartBulkLockPlural'       => __( '⚡ Smart folders locked.', 'kookoa-folders' ),
			'smartBulkDeleted'          => __( '⚡ Smart folder deleted.', 'kookoa-folders' ),
			'smartBulkDeletedPlural'    => __( '⚡ Smart folders deleted.', 'kookoa-folders' ),
			'deleteSmartTitle'          => __( 'Delete', 'kookoa-folders' ) . '⚡' . __( 'Smart Folder', 'kookoa-folders' ),
			'deleteSmartMsg'            => __( 'Are you sure you want to delete this smart folder? The items inside will NOT be deleted.', 'kookoa-folders' ),
			'deleteBulkSmartTitle'      => __( 'Delete', 'kookoa-folders' ) . '⚡' . __( 'Smart Folders', 'kookoa-folders' ),
			'deleteBulkSmartMsg'        => __( 'Are you sure you want to delete the selected smart folders? The items inside will NOT be deleted.', 'kookoa-folders' ),

			// Smart folder rule tooltip + builder UI.
			'smartRulesTitle'           => __( '⚡ Smart Rules', 'kookoa-folders' ),
			'yes'                       => __( 'Yes', 'kookoa-folders' ),
			'no'                        => __( 'No', 'kookoa-folders' ),
			'rulesLabel'                => __( 'Rules', 'kookoa-folders' ),
			'removeRule'                => __( 'Remove', 'kookoa-folders' ),
			'dateFrom'                  => __( 'From', 'kookoa-folders' ),
			'dateTo'                    => __( 'To', 'kookoa-folders' ),

			// Media metadata + EXIF hover tooltip.
			'metaFileInfo'              => __( 'File Info', 'kookoa-folders' ),
			'metaSize'                  => __( 'Size', 'kookoa-folders' ),
			'metaWeight'                => __( 'Weight', 'kookoa-folders' ),
			'metaFormat'                => __( 'Format', 'kookoa-folders' ),
			'metaDate'                  => __( 'Date', 'kookoa-folders' ),
			'metaExifInfo'              => __( 'EXIF Info', 'kookoa-folders' ),
			'metaCamera'                => __( 'Camera', 'kookoa-folders' ),
			'metaAperture'              => __( 'Aperture', 'kookoa-folders' ),
			'metaShutter'               => __( 'Shutter', 'kookoa-folders' ),
			'metaIso'                   => __( 'ISO', 'kookoa-folders' ),
			'metaFocal'                 => __( 'Focal', 'kookoa-folders' ),

			// Migrate from other folder plugins (Settings → Import & Export).
			'migrateImporting'          => __( 'Importing...', 'kookoa-folders' ),
			'migrateImportFailed'       => __( 'Import failed.', 'kookoa-folders' ),
			'migrateStartImport'        => __( 'Start Import', 'kookoa-folders' ),
			'migrateImportedLabel'      => __( 'Imported.', 'kookoa-folders' ),
			'migrateErrorLabel'         => __( 'Error.', 'kookoa-folders' ),
			'migrateNetworkFailure'     => __( 'Network failure.', 'kookoa-folders' ),
			/* translators: %d: number of folders created during the import */
			'migrateFoldersCreatedOne'  => __( '%d folder created', 'kookoa-folders' ),
			/* translators: %d: number of folders created during the import */
			'migrateFoldersCreatedMany' => __( '%d folders created', 'kookoa-folders' ),
			/* translators: %d: number of items assigned during the import */
			'migrateItemsAssignedOne'   => __( '%d item assigned', 'kookoa-folders' ),
			/* translators: %d: number of items assigned during the import */
			'migrateItemsAssignedMany'  => __( '%d items assigned', 'kookoa-folders' ),
			/* translators: %d: number of items skipped because they were already organized */
			'migrateSkipped'            => __( '%d skipped (already organized)', 'kookoa-folders' ),
			/* translators: %d: number of warnings produced by the importer */
			'migrateWarningOne'         => __( '%d warning', 'kookoa-folders' ),
			/* translators: %d: number of warnings produced by the importer */
			'migrateWarningMany'        => __( '%d warnings', 'kookoa-folders' ),
			'migrateSeeBrowserConsole'  => __( 'see browser console.', 'kookoa-folders' ),
			/* translators: %s: source plugin name (e.g. "FileBird") */
			'migrateSourceStillActive'  => __( '%s is still active. Deactivate it now?', 'kookoa-folders' ),
			/* translators: %s: source plugin name (e.g. "FileBird") */
			'migrateDeactivateLabel'    => __( 'Deactivate %s', 'kookoa-folders' ),
			'migrateDeactivating'       => __( 'Deactivating...', 'kookoa-folders' ),
			'migrateDeactivated'        => __( 'Deactivated.', 'kookoa-folders' ),
			'migrateDeactivate'         => __( 'Deactivate', 'kookoa-folders' ),
			'migrateRemoveConfirm'      => __( "Remove the Migrate section permanently?\n\nThis cannot be undone from the UI. Use this only if you are done importing from other plugins and never want to see this section again.", 'kookoa-folders' ),
		);
	}

	/**
	 * Build JSON payload for builder/media modals (color rows + icon categories).
	 *
	 * Shared by `render_builder_modals()` (frontend builder / Elementor editor) and
	 * `KookoaWPF_Assets::enqueue_admin_assets()` (admin) so media modal dialogs can
	 * be created on-demand in JS when Divi strips hidden HTML.
	 *
	 * @return string|null JSON string or null when attachment isn't supported.
	 */
	public function get_builder_modal_json() {
		$supported = kookoawpf()->get_supported_post_types();
		if ( ! in_array( 'attachment', $supported, true ) ) {
			return null;
		}

		$custom_colors   = get_option( 'kookoawpf_custom_colors', array() );
		$icon_blocks_off = get_option( 'kookoawpf_icon_blocks_disabled', array() );
		$color_rows      = array(
			array( '#39FF14', '#34C759', '#00BCD4', '#007AFF', '#9966FF', '#FF66FF' ),
			array( '#FF3300', '#FF9500', '#FFCC00', '#CC9933', '#FFCCFF' ),
			array( '#999999', '#FFFFFF', '#000000' ),
		);
		$icon_categories = array(
			'folders'     => array(
				'label' => __( 'Folders', 'kookoa-folders' ),
				'icons' => array( '⭐', '🔒', '🔗', '🗂️', '📂', '📌', '📍', '✂️', '❓', '🔍', '📚', '🧱', '🧻', '🧰' ),
			),
			'images'      => array(
				'label' => __( 'Images', 'kookoa-folders' ),
				'icons' => array( '🖼️', '🌄', '🎨', '🧩', '🏞️', '🌇', '📷' ),
			),
			'documents'   => array(
				'label' => __( 'Documents', 'kookoa-folders' ),
				'icons' => array( '📄', '📝', '📕', '📘', '📗', '📒', '📊', '📑', '📰', '📋', '🧮', '📶', '📈', '📉' ),
			),
			'video-audio' => array(
				'label' => __( 'Video/Audio', 'kookoa-folders' ),
				'icons' => array( '🎬', '▶️', '🎞️', '🎵', '🎧', '💿', '📀' ),
			),
			'tech'        => array(
				'label' => __( 'Tech', 'kookoa-folders' ),
				'icons' => array( '⚙️', '🧠', '🔧', '💻', '🖥️', '📱', '🌐', '📟', '🤖', '🧭', '🔋', '🛡️', '💡', '🧲' ),
			),
			'actions'     => array(
				'label' => __( 'Actions', 'kookoa-folders' ),
				'icons' => array( '➕', '📥', '✏️', '🗑️', '🔍', '🏷️', '🔄', '✅', '✴️', '🚀', '🧹', '♻️', '🧬', '🔥' ),
			),
			'states'      => array(
				'label' => __( 'States', 'kookoa-folders' ),
				'icons' => array( '✔️', '❌', '🌍', '⏳', '⚠️', '🕘', '🎯', '🔴', '🟢', '🟡', '🟠', '🔵', '🟣', '⚪' ),
			),
			'special'     => array(
				'label' => __( 'Special', 'kookoa-folders' ),
				'icons' => array( '🐹', '🐭', '🐶', '🐼', '🍒', '🍉', '🍎', '❤️', '💛', '🩵', '🤍', '🎁', '🛒', '☎️', '⏰', '🚚', '💰', '🌟', '✨', '🔆', '💩', '😍', '😁', '😎', '🤮', '👽', '👻', '🤡', '👍', '👎', '👆', '👌', '✌️', '👈', '🤘' ),
			),
		);
		// Filter disabled icon blocks.
		foreach ( (array) $icon_blocks_off as $off ) {
			unset( $icon_categories[ $off ] );
		}
		// JSON_HEX_TAG/AMP/APOS/QUOT: escape <, >, &, ', " as \uXXXX so the payload
		// is safe to inline inside a <script> tag (prevents </script> break-outs and
		// HTML entity confusion).
		$json = wp_json_encode(
			array(
				'colorRows'      => $color_rows,
				'customColors'   => $custom_colors,
				'iconCategories' => $icon_categories,
			),
			JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT
		);
		return false === $json ? null : $json;
	}

	/**
	 * Render modal HTML on frontend builder pages (wp_footer).
	 * Delegates to KookoaWPF_Admin::render_media_modal_modals().
	 */
	public function render_builder_modals(): void {
		// RBAC gate — only allowed roles see modals.
		if ( ! kookoawpf_user_has_access() ) {
			return; }

		$json = $this->get_builder_modal_json();
		if ( null === $json ) {
			return;
		}

		// Divi's output buffer strips display:none elements from the DOM.
		// Pass modal data as JSON and let JS create them on demand. Use the
		// core inline-script-tag helper so the script payload goes through
		// WordPress's standard inline-script sanitization layer instead of
		// a raw <script> echo.
		wp_print_inline_script_tag( 'window.kookoawpfBuilderModals = ' . $json . ';' );
	}
}
