<?php
/**
 * Favicon Generator Module
 *
 * Generate all favicon formats from a single image.
 *
 * @package BlaminhorEssentials
 */

// Prevent direct access.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * Favicon Generator module class
 */
class Blaminhor_Essentials_Module_Favicon extends Blaminhor_Essentials_Module {

    /**
     * Module ID
     *
     * @var string
     */
    protected $id = 'favicon';

    /**
     * Module name
     *
     * @var string
     */
    protected $name = 'Favicon Generator';

    /**
     * Favicon sizes to generate
     *
     * @var array
     */
    private $favicon_sizes = array(
        'favicon-16x16.png'         => array( 'width' => 16, 'height' => 16 ),
        'favicon-32x32.png'         => array( 'width' => 32, 'height' => 32 ),
        'favicon-48x48.png'         => array( 'width' => 48, 'height' => 48 ),
        'apple-touch-icon.png'      => array( 'width' => 180, 'height' => 180 ),
        'android-chrome-192x192.png'=> array( 'width' => 192, 'height' => 192 ),
        'android-chrome-512x512.png'=> array( 'width' => 512, 'height' => 512 ),
        'mstile-150x150.png'        => array( 'width' => 150, 'height' => 150 ),
    );

    /**
     * Initialize module
     */
    protected function init() {
        $this->name        = __( 'Favicon Generator', 'blaminhor-essentials' );
        $this->description = __( 'Generate all favicon formats from a single image.', 'blaminhor-essentials' );
    }

    /**
     * Get default settings
     *
     * @return array
     */
    protected function get_default_settings() {
        return array(
            'source_image_id' => 0,
            'theme_color'     => '#ffffff',
            'bg_color'        => '#ffffff',
            'generated'       => false,
        );
    }

    /**
     * Register hooks
     */
    protected function register_hooks() {
        add_action( 'admin_init', array( $this, 'handle_settings_submission' ) );
        add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_media_scripts' ) );

        // Output favicon meta tags.
        if ( $this->get_setting( 'generated', false ) ) {
            add_action( 'wp_head', array( $this, 'output_favicon_meta' ), 1 );
            add_action( 'admin_head', array( $this, 'output_favicon_meta' ), 1 );
            add_action( 'login_head', array( $this, 'output_favicon_meta' ), 1 );

            // Remove default WordPress site icon.
            add_filter( 'get_site_icon_url', '__return_empty_string' );

            // Handle manifest and browserconfig requests.
            add_action( 'init', array( $this, 'handle_manifest_requests' ) );
        }
    }

    /**
     * Enqueue media scripts for image selection
     *
     * @param string $hook Current admin page hook.
     */
    public function enqueue_media_scripts( $hook ) {
        if ( strpos( $hook, 'blaminhor-essentials' ) === false ) {
            return;
        }

        wp_enqueue_media();
    }

    /**
     * Handle manifest and browserconfig requests
     */
    public function handle_manifest_requests() {
        $request_uri = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';

        if ( strpos( $request_uri, '/site.webmanifest' ) !== false ) {
            $this->output_webmanifest();
            exit;
        }

        if ( strpos( $request_uri, '/browserconfig.xml' ) !== false ) {
            $this->output_browserconfig();
            exit;
        }
    }

    /**
     * Get favicon directory path
     *
     * @return string
     */
    private function get_favicon_dir() {
        $upload_dir = wp_upload_dir();
        return $upload_dir['basedir'] . '/blaminhor-essentials/favicon/';
    }

    /**
     * Get favicon directory URL
     *
     * @return string
     */
    private function get_favicon_url() {
        $upload_dir = wp_upload_dir();
        return $upload_dir['baseurl'] . '/blaminhor-essentials/favicon/';
    }

    /**
     * Create favicon directory if it doesn't exist
     *
     * @return bool
     */
    private function ensure_favicon_dir() {
        $dir = $this->get_favicon_dir();

        if ( ! file_exists( $dir ) ) {
            return wp_mkdir_p( $dir );
        }

        return true;
    }

    /**
     * Generate all favicon files from source image
     *
     * @param int $attachment_id Source image attachment ID.
     * @return array|WP_Error Array of generated files or error.
     */
    private function generate_favicons( $attachment_id ) {
        if ( ! $this->ensure_favicon_dir() ) {
            return new WP_Error( 'dir_error', __( 'Could not create favicon directory.', 'blaminhor-essentials' ) );
        }

        $source_path = get_attached_file( $attachment_id );

        if ( ! $source_path || ! file_exists( $source_path ) ) {
            return new WP_Error( 'source_error', __( 'Source image not found.', 'blaminhor-essentials' ) );
        }

        // Check if GD or Imagick is available.
        $editor = wp_get_image_editor( $source_path );

        if ( is_wp_error( $editor ) ) {
            return new WP_Error( 'editor_error', __( 'Image processing not available. Please check your server configuration.', 'blaminhor-essentials' ) );
        }

        $generated_files = array();
        $favicon_dir     = $this->get_favicon_dir();

        // Generate each size.
        foreach ( $this->favicon_sizes as $filename => $size ) {
            $editor = wp_get_image_editor( $source_path );

            if ( is_wp_error( $editor ) ) {
                continue;
            }

            // Resize with crop to ensure exact dimensions.
            $resized = $editor->resize( $size['width'], $size['height'], true );

            if ( is_wp_error( $resized ) ) {
                continue;
            }

            // Set quality.
            $editor->set_quality( 100 );

            // Save the file.
            $saved = $editor->save( $favicon_dir . $filename, 'image/png' );

            if ( ! is_wp_error( $saved ) ) {
                $generated_files[] = $filename;
            }
        }

        // Generate ICO file (using 48x48 PNG as base).
        $ico_result = $this->generate_ico_file( $favicon_dir . 'favicon-48x48.png', $favicon_dir . 'favicon.ico' );
        if ( $ico_result ) {
            $generated_files[] = 'favicon.ico';
        }

        // Copy ICO to root if possible.
        $this->copy_ico_to_root( $favicon_dir . 'favicon.ico' );

        if ( empty( $generated_files ) ) {
            return new WP_Error( 'generation_error', __( 'Could not generate any favicon files.', 'blaminhor-essentials' ) );
        }

        return $generated_files;
    }

    /**
     * Generate ICO file from PNG
     *
     * Creates a simple ICO file with multiple sizes.
     *
     * @param string $png_source Path to source PNG.
     * @param string $ico_dest   Path to destination ICO.
     * @return bool
     */
    private function generate_ico_file( $png_source, $ico_dest ) {
        if ( ! file_exists( $png_source ) ) {
            return false;
        }

        // Load the source image.
        $source = @imagecreatefrompng( $png_source );
        if ( ! $source ) {
            return false;
        }

        $sizes = array( 16, 32, 48 );
        $images = array();

        foreach ( $sizes as $size ) {
            $img = imagecreatetruecolor( $size, $size );

            // Enable alpha channel.
            imagealphablending( $img, false );
            imagesavealpha( $img, true );

            // Fill with transparent.
            $transparent = imagecolorallocatealpha( $img, 0, 0, 0, 127 );
            imagefill( $img, 0, 0, $transparent );

            // Enable alpha blending for resampling.
            imagealphablending( $img, true );

            // Resample.
            imagecopyresampled(
                $img,
                $source,
                0, 0, 0, 0,
                $size, $size,
                imagesx( $source ),
                imagesy( $source )
            );

            $images[ $size ] = $img;
        }

        imagedestroy( $source );

        // Build ICO file.
        $ico_data = $this->build_ico_data( $images );

        // Clean up images.
        foreach ( $images as $img ) {
            imagedestroy( $img );
        }

        if ( $ico_data ) {
            return (bool) file_put_contents( $ico_dest, $ico_data );
        }

        return false;
    }

    /**
     * Build ICO file data from GD images
     *
     * @param array $images Array of GD image resources keyed by size.
     * @return string|false ICO file data or false on failure.
     */
    private function build_ico_data( $images ) {
        $image_count = count( $images );

        if ( $image_count === 0 ) {
            return false;
        }

        // ICO header: 6 bytes.
        $ico_header = pack( 'vvv', 0, 1, $image_count );

        $ico_directory = '';
        $ico_data      = '';
        $offset        = 6 + ( $image_count * 16 ); // Header + directory entries.

        foreach ( $images as $size => $img ) {
            // Get PNG data.
            ob_start();
            imagepng( $img );
            $png_data = ob_get_clean();

            $data_size = strlen( $png_data );

            // Directory entry: 16 bytes.
            $ico_directory .= pack(
                'CCCCvvVV',
                $size < 256 ? $size : 0, // Width (0 means 256).
                $size < 256 ? $size : 0, // Height (0 means 256).
                0,                        // Color palette.
                0,                        // Reserved.
                1,                        // Color planes.
                32,                       // Bits per pixel.
                $data_size,               // Data size.
                $offset                   // Data offset.
            );

            $ico_data .= $png_data;
            $offset   += $data_size;
        }

        return $ico_header . $ico_directory . $ico_data;
    }

    /**
     * Try to copy favicon.ico to site root
     *
     * @param string $source_ico Path to source ICO file.
     */
    private function copy_ico_to_root( $source_ico ) {
        if ( ! file_exists( $source_ico ) ) {
            return;
        }

        $root_ico = ABSPATH . 'favicon.ico';

        // Only copy if we can write to root and there's no existing favicon.
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_is_writable -- No WP alternative for checking writability
        if ( is_writable( ABSPATH ) && ! file_exists( $root_ico ) ) {
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_copy
            @copy( $source_ico, $root_ico );
        }
    }

    /**
     * Delete all generated favicon files
     */
    private function delete_favicons() {
        $favicon_dir = $this->get_favicon_dir();

        if ( ! file_exists( $favicon_dir ) ) {
            return;
        }

        $files = glob( $favicon_dir . '*' );

        foreach ( $files as $file ) {
            if ( is_file( $file ) ) {
                wp_delete_file( $file );
            }
        }

        // Try to remove the directory.
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rmdir -- Simple directory removal after file cleanup
        @rmdir( $favicon_dir );

        // Try to remove favicon.ico from root if it was created by us.
        $root_ico = ABSPATH . 'favicon.ico';
        if ( file_exists( $root_ico ) ) {
            $favicon_ico = $favicon_dir . 'favicon.ico';
            // Only delete if sizes match (rough check that it's ours).
            if ( file_exists( $favicon_ico ) ) {
                wp_delete_file( $root_ico );
            }
        }
    }

    /**
     * Output favicon meta tags
     */
    public function output_favicon_meta() {
        $favicon_url = $this->get_favicon_url();
        $theme_color = $this->get_setting( 'theme_color', '#ffffff' );
        ?>
<!-- Blaminhor Essentials Favicon -->
<link rel="icon" type="image/png" sizes="48x48" href="<?php echo esc_url( $favicon_url . 'favicon-48x48.png' ); ?>">
<link rel="icon" type="image/png" sizes="32x32" href="<?php echo esc_url( $favicon_url . 'favicon-32x32.png' ); ?>">
<link rel="icon" type="image/png" sizes="16x16" href="<?php echo esc_url( $favicon_url . 'favicon-16x16.png' ); ?>">
<link rel="apple-touch-icon" sizes="180x180" href="<?php echo esc_url( $favicon_url . 'apple-touch-icon.png' ); ?>">
<link rel="manifest" href="<?php echo esc_url( home_url( '/site.webmanifest' ) ); ?>">
<meta name="msapplication-TileImage" content="<?php echo esc_url( $favicon_url . 'mstile-150x150.png' ); ?>">
<meta name="msapplication-TileColor" content="<?php echo esc_attr( $theme_color ); ?>">
<meta name="msapplication-config" content="<?php echo esc_url( home_url( '/browserconfig.xml' ) ); ?>">
<meta name="theme-color" content="<?php echo esc_attr( $theme_color ); ?>">
<!-- End Blaminhor Essentials Favicon -->
        <?php
    }

    /**
     * Output web manifest file
     */
    private function output_webmanifest() {
        $favicon_url = $this->get_favicon_url();
        $theme_color = $this->get_setting( 'theme_color', '#ffffff' );
        $bg_color    = $this->get_setting( 'bg_color', '#ffffff' );

        $manifest = array(
            'name'             => get_bloginfo( 'name' ),
            'short_name'       => get_bloginfo( 'name' ),
            'icons'            => array(
                array(
                    'src'   => $favicon_url . 'android-chrome-192x192.png',
                    'sizes' => '192x192',
                    'type'  => 'image/png',
                ),
                array(
                    'src'   => $favicon_url . 'android-chrome-512x512.png',
                    'sizes' => '512x512',
                    'type'  => 'image/png',
                ),
            ),
            'theme_color'      => $theme_color,
            'background_color' => $bg_color,
            'display'          => 'standalone',
        );

        header( 'Content-Type: application/manifest+json; charset=utf-8' );
        echo wp_json_encode( $manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
    }

    /**
     * Output browserconfig.xml for Windows tiles
     */
    private function output_browserconfig() {
        $favicon_url = $this->get_favicon_url();
        $theme_color = $this->get_setting( 'theme_color', '#ffffff' );

        header( 'Content-Type: application/xml; charset=utf-8' );
        echo '<?xml version="1.0" encoding="utf-8"?>' . "\n";
        ?>
<browserconfig>
    <msapplication>
        <tile>
            <square150x150logo src="<?php echo esc_url( $favicon_url . 'mstile-150x150.png' ); ?>"/>
            <TileColor><?php echo esc_html( $theme_color ); ?></TileColor>
        </tile>
    </msapplication>
</browserconfig>
        <?php
    }

    /**
     * Process settings
     *
     * @param array $data Form data.
     */
    protected function process_settings( $data ) {
        $settings = $this->settings;

        // Handle favicon generation.
        if ( isset( $data['generate_favicon'] ) ) {
            $image_id = isset( $data['source_image_id'] ) ? absint( $data['source_image_id'] ) : 0;

            if ( $image_id <= 0 ) {
                add_action( 'admin_notices', function () {
                    blaminhor_essentials_admin_notice( __( 'Please select an image from the media library.', 'blaminhor-essentials' ), 'error' );
                } );
                return;
            }

            // Validate image.
            $mime_type = get_post_mime_type( $image_id );
            $allowed   = array( 'image/png', 'image/jpeg', 'image/gif', 'image/webp' );

            if ( ! in_array( $mime_type, $allowed, true ) ) {
                add_action( 'admin_notices', function () {
                    blaminhor_essentials_admin_notice( __( 'Please select a valid image (PNG, JPEG, GIF, or WebP).', 'blaminhor-essentials' ), 'error' );
                } );
                return;
            }

            // Check minimum dimensions.
            $metadata = wp_get_attachment_metadata( $image_id );
            if ( isset( $metadata['width'] ) && isset( $metadata['height'] ) ) {
                if ( $metadata['width'] < 512 || $metadata['height'] < 512 ) {
                    add_action( 'admin_notices', function () {
                        blaminhor_essentials_admin_notice( __( 'Image must be at least 512x512 pixels for best results.', 'blaminhor-essentials' ), 'warning' );
                    } );
                }
            }

            // Get colors.
            $theme_color = isset( $data['theme_color'] ) ? sanitize_hex_color( $data['theme_color'] ) : '#ffffff';
            $bg_color    = isset( $data['bg_color'] ) ? sanitize_hex_color( $data['bg_color'] ) : '#ffffff';

            // Delete old favicons first.
            $this->delete_favicons();

            // Generate new favicons.
            $result = $this->generate_favicons( $image_id );

            if ( is_wp_error( $result ) ) {
                $error_message = $result->get_error_message();
                add_action( 'admin_notices', function () use ( $error_message ) {
                    blaminhor_essentials_admin_notice( $error_message, 'error' );
                } );
                return;
            }

            // Save settings.
            $settings['source_image_id'] = $image_id;
            $settings['theme_color']     = $theme_color ? $theme_color : '#ffffff';
            $settings['bg_color']        = $bg_color ? $bg_color : '#ffffff';
            $settings['generated']       = true;

            $this->save_settings( $settings );

            $count = count( $result );
            add_action( 'admin_notices', function () use ( $count ) {
                /* translators: %d: number of files generated */
                blaminhor_essentials_admin_notice( sprintf( __( 'Favicon generated successfully! %d files created.', 'blaminhor-essentials' ), $count ), 'success' );
            } );
            return;
        }

        // Handle favicon removal.
        if ( isset( $data['remove_favicon'] ) ) {
            $this->delete_favicons();

            $settings['source_image_id'] = 0;
            $settings['generated']       = false;

            $this->save_settings( $settings );

            add_action( 'admin_notices', function () {
                blaminhor_essentials_admin_notice( __( 'Favicon removed.', 'blaminhor-essentials' ), 'success' );
            } );
            return;
        }
    }

    /**
     * Render settings page
     */
    public function render_settings_page() {
        $source_image_id = $this->get_setting( 'source_image_id', 0 );
        $theme_color     = $this->get_setting( 'theme_color', '#ffffff' );
        $bg_color        = $this->get_setting( 'bg_color', '#ffffff' );
        $favicon_url     = $this->get_favicon_url();

        // Check if favicon is actually generated (setting AND files exist).
        $is_generated = $this->get_setting( 'generated', false ) && file_exists( $this->get_favicon_dir() . 'favicon-32x32.png' );

        $source_image_url = '';
        if ( $source_image_id ) {
            $source_image_url = wp_get_attachment_image_url( $source_image_id, 'thumbnail' );
        }
        ?>
        <div class="wrap blaminhor-essentials-wrap">
            <div class="blaminhor-essentials-header">
                <h1><?php esc_html_e( 'Favicon Generator', 'blaminhor-essentials' ); ?></h1>
                <p class="blaminhor-essentials-tagline"><?php esc_html_e( 'Generate all favicon formats from a single image.', 'blaminhor-essentials' ); ?></p>
            </div>

            <div class="blaminhor-essentials-tabs-wrapper">
                <?php if ( $is_generated ) : ?>
                    <!-- Current Favicon Status -->
                    <div class="ap-favicon-status ap-favicon-active">
                        <div class="ap-favicon-status-icon">
                            <span class="dashicons dashicons-yes-alt"></span>
                        </div>
                        <div class="ap-favicon-status-content">
                            <h3><?php esc_html_e( 'Favicon Active', 'blaminhor-essentials' ); ?></h3>
                            <p><?php esc_html_e( 'Your favicon is configured and active on all pages.', 'blaminhor-essentials' ); ?></p>
                        </div>
                        <div class="ap-favicon-preview">
                            <?php
                            $preview_url = $source_image_url ? $source_image_url : ( file_exists( $this->get_favicon_dir() . 'favicon-48x48.png' ) ? $favicon_url . 'favicon-48x48.png' : '' );
                            if ( $preview_url ) :
                            ?>
                                <img src="<?php echo esc_url( $preview_url ); ?>" alt="Favicon" width="48" height="48">
                            <?php else : ?>
                                <span class="dashicons dashicons-format-image" class="ap-text-light-gray" style="font-size: 48px; width: 48px; height: 48px;"></span>
                            <?php endif; ?>
                        </div>
                    </div>

                    <!-- Generated Files -->
                    <div class="ap-section">
                        <h3><?php esc_html_e( 'Generated Files', 'blaminhor-essentials' ); ?></h3>
                        <div class="ap-favicon-files">
                            <?php
                            $files = array(
                                'favicon.ico'              => __( 'Browser Favicon', 'blaminhor-essentials' ),
                                'favicon-16x16.png'        => __( 'Small Icon (16px)', 'blaminhor-essentials' ),
                                'favicon-32x32.png'        => __( 'Standard Icon (32px)', 'blaminhor-essentials' ),
                                'favicon-48x48.png'        => __( 'Large Icon (48px)', 'blaminhor-essentials' ),
                                'apple-touch-icon.png'     => __( 'Apple Touch Icon (180px)', 'blaminhor-essentials' ),
                                'android-chrome-192x192.png' => __( 'Android Chrome (192px)', 'blaminhor-essentials' ),
                                'android-chrome-512x512.png' => __( 'Android Chrome Large (512px)', 'blaminhor-essentials' ),
                                'mstile-150x150.png'       => __( 'Windows Tile (150px)', 'blaminhor-essentials' ),
                            );

                            foreach ( $files as $filename => $label ) :
                                $file_path = $this->get_favicon_dir() . $filename;
                                $file_url  = $favicon_url . $filename;
                                $exists    = file_exists( $file_path );
                            ?>
                                <div class="ap-favicon-file <?php echo esc_attr( $exists ? '' : 'ap-file-missing' ); ?>">
                                    <span class="dashicons <?php echo esc_attr( $exists ? 'dashicons-yes' : 'dashicons-no' ); ?>"></span>
                                    <span class="ap-file-label"><?php echo esc_html( $label ); ?></span>
                                    <?php if ( $exists ) : ?>
                                        <a href="<?php echo esc_url( $file_url ); ?>" target="_blank" class="ap-file-link">
                                            <code><?php echo esc_html( $filename ); ?></code>
                                        </a>
                                    <?php endif; ?>
                                </div>
                            <?php endforeach; ?>
                        </div>
                    </div>

                    <!-- Actions -->
                    <div class="ap-section">
                        <h3><?php esc_html_e( 'Actions', 'blaminhor-essentials' ); ?></h3>
                        <form method="post" class="ap-inline-form">
                            <?php $this->render_nonce_field(); ?>
                            <input type="hidden" name="remove_favicon" value="1">
                            <button type="submit" class="button button-secondary ap-btn-icon"
                                    onclick="return confirm('<?php esc_attr_e( 'Remove the favicon? This will delete all generated files.', 'blaminhor-essentials' ); ?>');">
                                <span class="dashicons dashicons-trash"></span>
                                <?php esc_html_e( 'Remove Favicon', 'blaminhor-essentials' ); ?>
                            </button>
                        </form>
                    </div>

                    <hr>
                <?php endif; ?>

                <!-- Generate New Favicon -->
                <div class="ap-section">
                    <h3><?php echo $is_generated ? esc_html__( 'Replace Favicon', 'blaminhor-essentials' ) : esc_html__( 'Generate Favicon', 'blaminhor-essentials' ); ?></h3>
                    <p class="description">
                        <?php esc_html_e( 'Select a square image (at least 512x512 pixels) from your media library. PNG with transparency is recommended.', 'blaminhor-essentials' ); ?>
                    </p>

                    <form method="post" class="ap-mt-lg">
                        <?php $this->render_nonce_field(); ?>
                        <input type="hidden" name="generate_favicon" value="1">
                        <input type="hidden" name="source_image_id" id="source_image_id" value="<?php echo esc_attr( $source_image_id ); ?>">

                        <table class="form-table">
                            <tr>
                                <th scope="row">
                                    <label><?php esc_html_e( 'Source Image', 'blaminhor-essentials' ); ?> <span class="required">*</span></label>
                                </th>
                                <td>
                                    <div class="ap-image-selector">
                                        <div id="ap-image-preview" class="ap-image-preview <?php echo esc_attr( $source_image_url ? '' : 'ap-no-image' ); ?>">
                                            <?php if ( $source_image_url ) : ?>
                                                <img src="<?php echo esc_url( $source_image_url ); ?>" alt="">
                                            <?php else : ?>
                                                <span class="dashicons dashicons-format-image"></span>
                                            <?php endif; ?>
                                        </div>
                                        <button type="button" id="ap-select-image" class="button">
                                            <?php esc_html_e( 'Select Image', 'blaminhor-essentials' ); ?>
                                        </button>
                                        <button type="button" id="ap-remove-image" class="button ap-hidden"<?php echo $source_image_url ? '' : ''; ?>>
                                            <?php esc_html_e( 'Remove', 'blaminhor-essentials' ); ?>
                                        </button>
                                    </div>
                                    <p class="description"><?php esc_html_e( 'Recommended: Square PNG image, 512x512 pixels or larger.', 'blaminhor-essentials' ); ?></p>
                                </td>
                            </tr>
                            <tr>
                                <th scope="row">
                                    <label for="theme_color"><?php esc_html_e( 'Theme Color', 'blaminhor-essentials' ); ?></label>
                                </th>
                                <td>
                                    <span class="blaminhor-essentials-color-control">
                                        <input type="color" id="theme_color" name="theme_color" value="<?php echo esc_attr( $theme_color ); ?>" class="blaminhor-essentials-color-swatch">
                                        <input type="text" value="<?php echo esc_attr( $theme_color ); ?>" class="blaminhor-essentials-color-hex" maxlength="7" pattern="^#[0-9A-Fa-f]{6}$" aria-label="<?php esc_attr_e( 'Hex color value', 'blaminhor-essentials' ); ?>">
                                    </span>
                                    <p class="description"><?php esc_html_e( 'Used for browser UI elements and Windows tiles.', 'blaminhor-essentials' ); ?></p>
                                </td>
                            </tr>
                            <tr>
                                <th scope="row">
                                    <label for="bg_color"><?php esc_html_e( 'Background Color', 'blaminhor-essentials' ); ?></label>
                                </th>
                                <td>
                                    <span class="blaminhor-essentials-color-control">
                                        <input type="color" id="bg_color" name="bg_color" value="<?php echo esc_attr( $bg_color ); ?>" class="blaminhor-essentials-color-swatch">
                                        <input type="text" value="<?php echo esc_attr( $bg_color ); ?>" class="blaminhor-essentials-color-hex" maxlength="7" pattern="^#[0-9A-Fa-f]{6}$" aria-label="<?php esc_attr_e( 'Hex color value', 'blaminhor-essentials' ); ?>">
                                    </span>
                                    <p class="description"><?php esc_html_e( 'Background color for Android splash screen.', 'blaminhor-essentials' ); ?></p>
                                </td>
                            </tr>
                        </table>

                        <p class="submit">
                            <button type="submit" class="button button-primary ap-btn-icon" id="ap-generate-btn">
                                <span class="dashicons dashicons-admin-appearance"></span>
                                <?php echo $is_generated ? esc_html__( 'Regenerate Favicon', 'blaminhor-essentials' ) : esc_html__( 'Generate Favicon', 'blaminhor-essentials' ); ?>
                            </button>
                        </p>
                    </form>
                </div>

                <!-- Info -->
                <div class="blaminhor-essentials-notice info ap-mt-lg">
                    <strong><?php esc_html_e( 'What gets generated?', 'blaminhor-essentials' ); ?></strong><br>
                    <?php esc_html_e( 'This module generates all favicon formats needed for modern browsers, iOS, Android, and Windows, including:', 'blaminhor-essentials' ); ?>
                    <ul style="margin: 10px 0 0 20px; list-style: disc;">
                        <li><?php esc_html_e( 'Standard favicon.ico for browsers', 'blaminhor-essentials' ); ?></li>
                        <li><?php esc_html_e( 'PNG icons in multiple sizes', 'blaminhor-essentials' ); ?></li>
                        <li><?php esc_html_e( 'Apple Touch Icon for iOS devices', 'blaminhor-essentials' ); ?></li>
                        <li><?php esc_html_e( 'Android Chrome icons and web manifest', 'blaminhor-essentials' ); ?></li>
                        <li><?php esc_html_e( 'Windows tile icon and browserconfig.xml', 'blaminhor-essentials' ); ?></li>
                    </ul>
                </div>
            </div>
        </div>
        <?php
    }

    /**
     * Enqueue module-specific assets
     *
     * @param string $hook Current admin page hook.
     */
    public function enqueue_assets( $hook ) {
        // Only load on this module's page.
        if ( strpos( $hook, 'blaminhor-essentials-favicon' ) === false ) {
            return;
        }

        wp_enqueue_media();

        $config = array(
            'strings' => array(
                'selectTitle' => __( 'Select Favicon Image', 'blaminhor-essentials' ),
                'useImage'    => __( 'Use this image', 'blaminhor-essentials' ),
            ),
        );

        wp_add_inline_script(
            'blaminhor-essentials-modules',
            'jQuery(document).ready(function($) { BlaminhorEssentialsFavicon.init(' . wp_json_encode( $config ) . '); });'
        );
    }
}
