<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * 管理画面のビュー (描画) 層。
 *
 * メインページ・ウィザード・各タブ (設定/プロバイダ/画像/システムプロンプト/
 * タスク/ログ) の描画と、描画用ヘルパ・通知 notice をまとめた層。リクエスト処理
 * (AIAP_Admin_Controller) や AJAX/実行エンジン (AIAP_Admin) から描画ロジックを
 * 分離する (Phase 3 ステップ4)。
 *
 * 共有グルー (メニュースラッグ・nonce・USER_META 定数・プロバイダ定義の静的
 * プロパティ) は AIAP_Admin に残り、本クラスは AIAP_Admin::MENU_SLUG のように
 * 明示参照する。エントリポイント render_page はメニューコールバックとして、
 * maybe_render_* は admin_notices フックとして AIAP_Admin から登録される。
 */
class AIAP_Admin_View {

    /**
     * AUTH_KEY 未定義環境向けの管理画面 notice。
     *
     * AIAP 管理画面のみで表示する (他のページに出すと全管理者を混乱させる)。
     * dismissible にして頻繁に再表示されないようにする。
     */
    public static function maybe_render_auth_key_warning() {
        // current_user_can で権限をチェック
        if ( ! current_user_can( 'manage_options' ) ) {
            return;
        }
        // AIAP 配下のページのみで出す (screen ID は menu slug を含む)
        $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
        if ( ! $screen || strpos( (string) $screen->id, AIAP_Admin::MENU_SLUG ) === false ) {
            return;
        }
        // AUTH_KEY と SECURE_AUTH_KEY のいずれかが空 / 未定義なら警告
        $auth_missing = ! defined( 'AUTH_KEY' ) || AUTH_KEY === '';
        if ( ! $auth_missing ) {
            return;
        }
        ?>
        <div class="notice notice-error is-dismissible">
            <p>
                <strong><?php echo esc_html( __( 'AI Auto Poster: AUTH_KEY is not configured', 'ai-auto-poster' ) ); ?></strong>
            </p>
            <p>
                <?php echo esc_html( __( 'WordPress security keys (AUTH_KEY) are missing in wp-config.php. Without them, AI Auto Poster cannot encrypt your API keys at rest, so saving settings will silently clear them. Generate fresh keys at https://api.wordpress.org/secret-key/1.1/salt/ and paste them into wp-config.php, then re-enter your API keys.', 'ai-auto-poster' ) ); ?>
            </p>
        </div>
        <?php
    }

    /**
     * AIAP_Model_Sync が記録した discontinued モデルの警告 notice。
     *
     * AIAP 管理画面のみで表示する。プロバイダ側で saved_model が利用不能になっていれば
     * その情報をユーザーに伝え、設定画面のモデル選択を促す。
     *
     * 設定画面側 (render_provider) には既存の inline 警告 ($discontinued) が出るが、
     * それは設定画面を開いたときのみ。本 notice は AIAP 全ページで気付かせる役割。
     */
    public static function maybe_render_discontinued_model_warning() {
        if ( ! current_user_can( 'manage_options' ) ) {
            return;
        }
        if ( ! class_exists( 'AIAP_Model_Sync' ) ) {
            return;
        }
        $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
        if ( ! $screen || strpos( (string) $screen->id, AIAP_Admin::MENU_SLUG ) === false ) {
            return;
        }
        $discontinued = AIAP_Model_Sync::get_discontinued();
        if ( empty( $discontinued ) ) {
            return;
        }
        $items = array();
        foreach ( $discontinued as $provider => $model ) {
            $items[] = sprintf( '%s: %s', esc_html( $provider ), esc_html( $model ) );
        }
        $settings_url = admin_url( 'admin.php?page=' . AIAP_Admin::MENU_SLUG . '&tab=provider' );
        ?>
        <div class="notice notice-warning is-dismissible">
            <p>
                <strong><?php echo esc_html( __( 'AI Auto Poster: some selected models are no longer available', 'ai-auto-poster' ) ); ?></strong>
            </p>
            <p>
                <?php echo esc_html( __( 'The weekly model check detected that the following models are not in the provider\'s current list, which usually means they have been deprecated or retired:', 'ai-auto-poster' ) ); ?>
            </p>
            <ul style="list-style: disc; padding-left: 1.5em;">
                <?php foreach ( $items as $line ) : ?>
                    <li><?php echo $line; // already escaped in the sprintf above ?></li>
                <?php endforeach; ?>
            </ul>
            <p>
                <a href="<?php echo esc_url( $settings_url ); ?>" class="button button-primary"><?php echo esc_html( __( 'Open AI Provider settings', 'ai-auto-poster' ) ); ?></a>
            </p>
        </div>
        <?php
    }

    public static function tab_label( $key ) {
        $label = self::resolve_dynamic_key( $key );
        return preg_replace( '/^[^\p{L}\p{N}]+/u', '', $label );
    }

    public static function meta_label( $meta ) {
        // プロバイダ名(Claude, OpenAI等)は両言語共通の英字表記
        // 'label' があればそれを使い、'label_key' があれば i18n で展開する
        if ( ! empty( $meta['label'] ) ) {
            return $meta['label'];
        }
        if ( ! empty( $meta['label_key'] ) ) {
            return self::resolve_dynamic_key( $meta['label_key'] );
        }
        return '';
    }

    /**
     * 動的キーを WordPress 標準翻訳に解決する
     *
     * 動的に組み立てられたキー(例: 'imgfmt_16_9', 'dedup_sens_high')を
     * switch で個別の __( '...', 'ai-auto-poster' ) に振り分けて翻訳する。
     * これにより WordPress.org の翻訳ツール (makepot) がソースから抽出可能になる。
     *
     * @param string $key
     * @return string 翻訳後の文字列(キーが未定義ならキー自体を返す)
     */
    public static function resolve_dynamic_key( $key ) {
        switch ( $key ) {
            // 曜日
            case 'mon': return __( 'Mon', 'ai-auto-poster' );
            case 'tue': return __( 'Tue', 'ai-auto-poster' );
            case 'wed': return __( 'Wed', 'ai-auto-poster' );
            case 'thu': return __( 'Thu', 'ai-auto-poster' );
            case 'fri': return __( 'Fri', 'ai-auto-poster' );
            case 'sat': return __( 'Sat', 'ai-auto-poster' );
            case 'sun': return __( 'Sun', 'ai-auto-poster' );
            case 'dow_mon': return __( 'Mon', 'ai-auto-poster' );
            case 'dow_tue': return __( 'Tue', 'ai-auto-poster' );
            case 'dow_wed': return __( 'Wed', 'ai-auto-poster' );
            case 'dow_thu': return __( 'Thu', 'ai-auto-poster' );
            case 'dow_fri': return __( 'Fri', 'ai-auto-poster' );
            case 'dow_sat': return __( 'Sat', 'ai-auto-poster' );
            case 'dow_sun': return __( 'Sun', 'ai-auto-poster' );

            // 投稿ステータス
            case 'draft':   return __( 'Draft',          'ai-auto-poster' );
            case 'pending': return __( 'Pending Review', 'ai-auto-poster' );
            case 'publish': return __( 'Publish',        'ai-auto-poster' );

            // 有効/無効
            case 'enabled':  return __( 'Enabled',  'ai-auto-poster' );
            case 'disabled': return __( 'Disabled', 'ai-auto-poster' );
            case 'activate':   return __( 'Activate',   'ai-auto-poster' );
            case 'deactivate': return __( 'Disable', 'ai-auto-poster' );
            case 'auto_posting_turned_on':  return __( 'Auto posting turned ON',  'ai-auto-poster' );
            case 'auto_posting_turned_off': return __( 'Auto posting turned OFF', 'ai-auto-poster' );

            // dedup_sens_*
            case 'dedup_sens_high':   return __( 'Strict (catch only barely similar)', 'ai-auto-poster' );
            case 'dedup_sens_medium': return __( 'Balanced',                            'ai-auto-poster' );
            case 'dedup_sens_low':    return __( 'Loose (only flag clearly similar)',  'ai-auto-poster' );

            // imgfmt_*
            case 'imgfmt_16_9': return __( 'Landscape (16:9) - Blog headers', 'ai-auto-poster' );
            case 'imgfmt_1_1':  return __( 'Square (1:1) - Social posts',     'ai-auto-poster' );
            case 'imgfmt_9_16': return __( 'Portrait (9:16) - Stories',       'ai-auto-poster' );
            case 'imgfmt_4_3':  return __( 'Wide (4:3) - Thumbnails',         'ai-auto-poster' );

            // imgqual_*
            case 'imgqual_low':    return __( 'Low - Faster & Cheaper',  'ai-auto-poster' );
            case 'imgqual_medium': return __( 'Medium - Balanced',       'ai-auto-poster' );
            case 'imgqual_high':   return __( 'High - Best Quality',     'ai-auto-poster' );

            // imgprov_*(画像プロバイダ名)
            case 'imgprov_dalle3':    return __( 'DALL-E 3',     'ai-auto-poster' );
            case 'imgprov_imagen':    return __( 'Imagen',       'ai-auto-poster' );
            case 'imgprov_stability': return __( 'Stability AI', 'ai-auto-poster' );
            case 'imgprov_flux':      return __( 'Flux',         'ai-auto-poster' );
            case 'imgprov_unsplash':  return __( 'Unsplash',     'ai-auto-poster' );
            case 'imgprov_pixabay':   return __( 'Pixabay',      'ai-auto-poster' );
            case 'imgprov_pexels':    return __( 'Pexels',       'ai-auto-poster' );
            case 'imgprov_openverse': return __( 'Openverse',    'ai-auto-poster' );

            // imgstyle_*(画像スタイル)
            case 'imgstyle_none':              return __( 'None (Default)',     'ai-auto-poster' );
            case 'imgstyle_natural':           return __( 'Natural',            'ai-auto-poster' );
            case 'imgstyle_vivid':             return __( 'Vivid',              'ai-auto-poster' );
            case 'imgstyle_realistic':         return __( 'Realistic',          'ai-auto-poster' );
            case 'imgstyle_cartoon':           return __( 'Cartoon',            'ai-auto-poster' );
            case 'imgstyle_anime':             return __( 'Anime',              'ai-auto-poster' );
            case 'imgstyle_3d-render':         return __( '3D Render',          'ai-auto-poster' );
            case 'imgstyle_3d-model':          return __( '3D Model',           'ai-auto-poster' );
            case 'imgstyle_watercolor':        return __( 'Watercolor',         'ai-auto-poster' );
            case 'imgstyle_oil-painting':      return __( 'Oil Painting',       'ai-auto-poster' );
            case 'imgstyle_flat-design':       return __( 'Flat Design',        'ai-auto-poster' );
            case 'imgstyle_pixel-art':         return __( 'Pixel Art',          'ai-auto-poster' );
            case 'imgstyle_analog-film':       return __( 'Analog Film',        'ai-auto-poster' );
            case 'imgstyle_cinematic':         return __( 'Cinematic',          'ai-auto-poster' );
            case 'imgstyle_comic-book':        return __( 'Comic Book',         'ai-auto-poster' );
            case 'imgstyle_digital-art':       return __( 'Digital Art',        'ai-auto-poster' );
            case 'imgstyle_enhance':           return __( 'Enhance',            'ai-auto-poster' );
            case 'imgstyle_fantasy-art':       return __( 'Fantasy Art',        'ai-auto-poster' );
            case 'imgstyle_isometric':         return __( 'Isometric',          'ai-auto-poster' );
            case 'imgstyle_line-art':          return __( 'Line Art',           'ai-auto-poster' );
            case 'imgstyle_low-poly':          return __( 'Low Poly',           'ai-auto-poster' );
            case 'imgstyle_modeling-compound': return __( 'Modeling Compound',  'ai-auto-poster' );
            case 'imgstyle_neon-punk':         return __( 'Neon Punk',          'ai-auto-poster' );
            case 'imgstyle_origami':           return __( 'Origami',            'ai-auto-poster' );
            case 'imgstyle_photographic':      return __( 'Photographic',       'ai-auto-poster' );
            case 'imgstyle_tile-texture':      return __( 'Tile Texture',       'ai-auto-poster' );

            // SEO グループ
            case 'seo_content_group':   return __( 'Content Optimization',     'ai-auto-poster' );
            case 'seo_image_group':     return __( 'Image Optimization',       'ai-auto-poster' );
            case 'seo_structure_group': return __( 'Site Structure',           'ai-auto-poster' );
            case 'seo_meta_group':      return __( 'Meta and Structured Data', 'ai-auto-poster' );
            case 'seo_other_group':     return __( 'Other Settings',           'ai-auto-poster' );

            // SEO 個別フィールド
            case 'seo_meta_desc':     return __( 'Auto-generate meta description',                'ai-auto-poster' );
            case 'seo_heading':       return __( 'Optimize heading structure',                    'ai-auto-poster' );
            case 'seo_focus_kw':      return __( 'Generate and apply focus keyword',              'ai-auto-poster' );
            case 'seo_faq':           return __( 'Auto-generate FAQ section',                     'ai-auto-poster' );
            case 'seo_toc':           return __( 'Auto-insert table of contents',                 'ai-auto-poster' );
            case 'seo_template':      return __( 'Apply article template',                        'ai-auto-poster' );
            case 'seo_img_alt':       return __( 'Auto-set image alt text',                       'ai-auto-poster' );
            case 'seo_img_webp':      return __( 'WebP conversion and compression',               'ai-auto-poster' );
            case 'seo_internal_link': return __( 'Auto-insert internal links',                    'ai-auto-poster' );
            case 'seo_auto_tag':      return __( 'Auto-generate and set tags',                    'ai-auto-poster' );
            case 'seo_related':       return __( 'Add related posts section',                     'ai-auto-poster' );
            case 'seo_schema':        return __( 'Auto-output Article JSON-LD schema',            'ai-auto-poster' );
            case 'seo_ogp':           return __( 'Auto-set OGP meta tags',                        'ai-auto-poster' );
            case 'seo_canonical':     return __( 'Set canonical URL',                             'ai-auto-poster' );
            case 'seo_plugin_link':   return __( 'Integrate with SEO plugins',                    'ai-auto-poster' );
            case 'seo_reading_time':  return __( 'Calculate and save reading time',               'ai-auto-poster' );
            case 'seo_sitemap_ping':  return __( 'Update XML sitemap and notify search engines',  'ai-auto-poster' );
            case 'seo_llms_txt':      return __( 'Generate llms.txt',                             'ai-auto-poster' );

            // タブ系
            case 'tab_settings':        return __( 'General Settings',     'ai-auto-poster' );
            case 'tab_provider':        return __( 'AI Providers',         'ai-auto-poster' );
            case 'tab_image_provider':  return __( 'Image AI Providers',   'ai-auto-poster' );
            case 'tab_image_settings':  return __( 'Image Settings',       'ai-auto-poster' );
            case 'tab_system_prompt':   return __( 'System Prompt',        'ai-auto-poster' );
            case 'tab_rss_feeds':       return __( 'RSS Feeds',            'ai-auto-poster' );
            case 'tab_prompts':         return __( 'Tasks',                'ai-auto-poster' );
            case 'tab_logs':            return __( 'Post history',         'ai-auto-poster' );
            case 'tab_run_logs':        return __( 'Execution log',        'ai-auto-poster' );
            case 'tab_quick_post':      return __( 'Quick Post',           'ai-auto-poster' );

            // notes (画像プロバイダの説明)
            case 'shared_openai':   return __( 'Uses the OpenAI API key already configured in AI Providers.', 'ai-auto-poster' );
            case 'shared_gemini':   return __( 'Uses the Gemini API key already configured in AI Providers.', 'ai-auto-poster' );
            case 'openverse_desc':  return __( 'Open-licensed image search by WordPress.org. Ready to use immediately.', 'ai-auto-poster' );
        }
        // 未定義: キーをそのまま返す(開発時の発見性重視)
        return $key;
    }

    public static function log_message( $log ) {
        // 新形式(キー+パラメータ)は Logger::format_message で展開、旧形式はメッセージそのまま
        $message = AIAP_Logger::format_message( $log );

        // 過去ログ互換: 英語UIで日本語の曜日が混入していたら英語表記に置換
        $locale = function_exists( 'determine_locale' ) ? determine_locale() : get_locale();
        $is_ja = ( strpos( $locale, 'ja' ) === 0 );
        if ( ! $is_ja ) {
            $dow_replace = array(
                '月曜日' => 'Mon', '火曜日' => 'Tue', '水曜日' => 'Wed', '木曜日' => 'Thu',
                '金曜日' => 'Fri', '土曜日' => 'Sat', '日曜日' => 'Sun',
            );
            $message = strtr( $message, $dow_replace );
        }

        return $message;
    }

    /**
     * ログ詳細 (<details>) で表示する context 配列のキー名を、ユーザー表示用に翻訳する。
     *
     * ログ生成側 (AIAP_AI_Client / AIAP_Image_Providers の log_request_payload 等) は
     * 機械可読な英語キー (provider / model / payload など) を context 配列に詰める。
     * これにより DB に保存されるログデータは後方互換性が保たれる (claude.md L19 遵守)。
     * 表示時のみ本関数を通して人間可読な日本語ラベルに変換する。
     *
     * 辞書に無いキーは大文字化した生のキー名をそのまま返す (= 新規 context キー追加時の
     * 安全フォールバック)。CSS の text-transform:uppercase はラテン文字のみに作用するため、
     * 翻訳済みの日本語ラベルは大文字化されず、そのまま表示される。
     *
     * @param string $key context 配列のキー名
     * @return string 翻訳済みラベル (or 辞書にないキーはそのまま)
     */
    public static function translate_context_key( $key ) {
        $key = (string) $key;
        switch ( $key ) {
            case 'provider':    return __( 'Provider',          'ai-auto-poster' );
            case 'model':       return __( 'Model',             'ai-auto-poster' );
            case 'is_manual':   return __( 'Manual run',        'ai-auto-poster' );
            case 'system_text': return __( 'System instruction','ai-auto-poster' );
            case 'user_prompt': return __( 'User prompt',       'ai-auto-poster' );
            case 'payload':     return __( 'Payload',           'ai-auto-poster' );
            case 'parameters':  return __( 'Parameters',        'ai-auto-poster' );
        }
        return $key;
    }

    public static function render_page() {
        if ( ! current_user_can( 'manage_options' ) ) return;

        // Phase 3: ウィザードを表示すべきならそちらに分岐
        if ( AIAP_Admin::should_show_wizard() ) {
            AIAP_Admin_View_Wizard::render_wizard();
            return;
        }

        $tab  = sanitize_key( wp_unslash( $_GET['tab'] ?? AIAP_Tabs::DEFAULT_TAB ) );
        $s    = AIAP_AI_Client::get_settings();
        $im   = AIAP_Image_Client::get_settings();
        ?>
        <?php
        $verified_providers = AIAP_Settings::verified_providers();
        $verified_keys = array_keys( $verified_providers );
        ?>
        <div class="wrap aiap-wrap" data-aiap-ajax-url="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>" data-aiap-nonce="<?php echo esc_attr( wp_create_nonce( AIAP_Admin::NONCE ) ); ?>" data-aiap-test-no-key="<?php echo esc_attr( __( 'Enter a key first', 'ai-auto-poster' ) ); ?>" data-aiap-btn-show="<?php echo esc_attr( __( 'Show', 'ai-auto-poster' ) ); ?>" data-aiap-btn-hide="<?php echo esc_attr( __( 'Hide', 'ai-auto-poster' ) ); ?>" data-aiap-verified="<?php echo esc_attr( wp_json_encode( $verified_keys ) ); ?>" data-aiap-not-tested-msg="<?php echo esc_attr( __( 'Please test the API key first.', 'ai-auto-poster' ) ); ?>">
            <div class="aiap-page-head">
                <h1 class="aiap-page-title">AI Auto Poster</h1>
            </div>
            <?php self::render_notices(); ?>
            <?php
            $tabs = array(
                AIAP_Tabs::SETTINGS => array(
                    'key'  => 'tab_settings',
                    'icon' => 'dashicons-admin-generic',
                ),
                AIAP_Tabs::QUICK_POST => array(
                    'key'  => 'tab_quick_post',
                    'icon' => 'dashicons-welcome-write-blog',
                ),
                AIAP_Tabs::PROVIDER => array(
                    'key'  => 'tab_provider',
                    'icon' => 'dashicons-edit-page',
                ),
                AIAP_Tabs::IMAGE_PROVIDER => array(
                    'key'  => 'tab_image_provider',
                    'icon' => 'dashicons-format-image',
                ),
                AIAP_Tabs::IMAGE_SETTINGS => array(
                    'key'  => 'tab_image_settings',
                    'icon' => 'dashicons-admin-tools',
                ),
                AIAP_Tabs::SYSTEM_PROMPT => array(
                    'key'  => 'tab_system_prompt',
                    'icon' => 'dashicons-editor-code',
                ),
                AIAP_Tabs::RSS_FEEDS => array(
                    'key'  => 'tab_rss_feeds',
                    'icon' => 'dashicons-rss',
                ),
                AIAP_Tabs::PROMPTS => array(
                    'key'  => 'tab_prompts',
                    'icon' => 'dashicons-list-view',
                ),
                AIAP_Tabs::LOGS => array(
                    'key'  => 'tab_logs',
                    'icon' => 'dashicons-media-text',
                ),
                AIAP_Tabs::RUN_LOGS => array(
                    'key'  => 'tab_run_logs',
                    'icon' => 'dashicons-media-document',
                ),
            );
            // サイドバーのセクションごとのグループ化 (#nav-redesign)
            $groups = array(
                'setup' => array(
                    'label' => __( 'Setup', 'ai-auto-poster' ),
                    'tabs'  => array( AIAP_Tabs::SETTINGS, AIAP_Tabs::PROVIDER, AIAP_Tabs::IMAGE_PROVIDER, AIAP_Tabs::RSS_FEEDS, AIAP_Tabs::IMAGE_SETTINGS, AIAP_Tabs::SYSTEM_PROMPT ),
                ),
                'operation' => array(
                    'label' => __( 'Operation', 'ai-auto-poster' ),
                    'tabs'  => array( AIAP_Tabs::PROMPTS, AIAP_Tabs::QUICK_POST, AIAP_Tabs::LOGS, AIAP_Tabs::RUN_LOGS ),
                ),
            );
            ?>
            <button type="button" class="aiap-sidebar-toggle" data-aiap-sidebar-toggle aria-label="<?php echo esc_attr( __( 'Toggle menu', 'ai-auto-poster' ) ); ?>" aria-expanded="false">
                <span class="dashicons dashicons-menu" aria-hidden="true"></span>
                <span class="aiap-sidebar-toggle-label"><?php echo esc_html( self::tab_label( $tabs[ $tab ]['key'] ?? 'tab_settings' ) ); ?></span>
            </button>

            <div class="aiap-shell">
                <aside class="aiap-sidebar" data-aiap-sidebar>
                    <nav class="aiap-tabs" role="tablist">
                        <?php foreach ( $groups as $group_key => $group ) : ?>
                            <div class="aiap-sidebar-section">
                                <div class="aiap-sidebar-section-title"><?php echo esc_html( $group['label'] ); ?></div>
                                <?php foreach ( $group['tabs'] as $slug ) : if ( ! isset( $tabs[ $slug ] ) ) continue; $meta = $tabs[ $slug ]; ?>
                                    <a href="?page=<?php echo esc_attr( AIAP_Admin::MENU_SLUG ); ?>&tab=<?php echo esc_attr( $slug ); ?>"
                                       class="aiap-tab<?php echo $tab === $slug ? ' is-active' : ''; ?>"
                                       role="tab"
                                       aria-selected="<?php echo $tab === $slug ? 'true' : 'false'; ?>">
                                        <span class="dashicons <?php echo esc_attr( $meta['icon'] ); ?> aiap-tab-icon" aria-hidden="true"></span>
                                        <span class="aiap-tab-label"><?php echo esc_html( self::tab_label( $meta['key'] ) ); ?></span>
                                    </a>
                                <?php endforeach; ?>
                            </div>
                        <?php endforeach; ?>
                    </nav>
                </aside>

                <main class="aiap-main">
                <div class="aiap-tab-panel">
            <?php
            switch ( $tab ) {
                case AIAP_Tabs::QUICK_POST:     AIAP_Admin_View_QuickPost::render_quick_post(); break;
                case AIAP_Tabs::PROVIDER:       AIAP_Admin_View_Provider::render_provider( $s ); break;
                case AIAP_Tabs::IMAGE_PROVIDER: AIAP_Admin_View_Provider::render_image_provider( $s, $im ); break;
                case AIAP_Tabs::IMAGE_SETTINGS: AIAP_Admin_View_Provider::render_image_settings( $im ); break;
                case AIAP_Tabs::PROMPTS:        AIAP_Admin_View_Tasks::render_tasks( $s ); break;
                case AIAP_Tabs::SYSTEM_PROMPT:  AIAP_Admin_View_Prompt::render_system_prompt( $s ); break;
                case AIAP_Tabs::RSS_FEEDS:      AIAP_Admin_RSS::render_rss_feeds(); break;
                case AIAP_Tabs::LOGS:           AIAP_Admin_View_Logs::render_logs(); break;
                case AIAP_Tabs::RUN_LOGS:       AIAP_Admin_View_Logs::render_run_logs(); break;
                default:               AIAP_Admin_View_Settings::render_settings( $s ); break;
            }
            ?>
                </div>
                </main>
            </div><!-- /.aiap-shell -->
        </div>
        <?php
    }

    private static function render_notices() {
        if ( ! empty( $_GET['aiap_msg'] ) ) {
            $msg     = sanitize_text_field( rawurldecode( wp_unslash( $_GET['aiap_msg'] ) ) );
            $raw     = sanitize_key( wp_unslash( $_GET['aiap_type'] ?? 'success' ) );
            $allowed = array( 'success', 'error', 'warning' );
            $type    = in_array( $raw, $allowed, true ) ? $raw : 'success';
            printf( '<div class="notice notice-%s is-dismissible"><p>%s</p></div>', esc_attr( $type ), esc_html( $msg ) );
        }
    }

}
