<?php
/**
 * AI で生成された投稿の一覧テーブル (WP_List_Table 継承)
 *
 * Logs タブの内容を「実行ログ(テキスト)」から「AI生成投稿の一覧(テーブルUI)」へ置き換えるための
 * 標準 WP_List_Table 実装。投稿は `_aiap_generated = 1` の postmeta で識別する。
 *
 * カラム:
 *   - created_at : 作成日時 (post_date, ソート可)
 *   - writer     : 生成に使った AI プロバイダ (Claude/OpenAI/Gemini 等、_aiap_provider)
 *   - task_name  : 紐付くタスクのプロンプト先頭30文字 / 手動投稿は "Manual"
 *   - status     : 投稿ステータス (公開 / 下書き / 予約 / 等、ソート可)
 *   - title      : 記事タイトル (リンク先=編集画面、ソート可)
 *   - image      : アイキャッチ画像のサムネ (60x60)
 *   - actions    : View / Edit ボタン
 *
 * 削除ハンドラは互換性のため admin 側に残すが、UI からは提供しない。
 */

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

if ( ! class_exists( 'WP_List_Table' ) ) {
    require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
}

class AIAP_Generated_Posts_Table extends WP_List_Table {

    public function __construct() {
        parent::__construct( array(
            'singular' => 'aiap_generated_post',
            'plural'   => 'aiap_generated_posts',
            'ajax'     => false,
        ) );
    }

    /**
     * テーブルに専用クラスを追加する。
     * モバイル(<=782px)で tfoot やその他のスタイル調整を確実に効かせるため。
     */
    protected function get_table_classes() {
        return array_merge( parent::get_table_classes(), array( 'aiap-generated-posts' ) );
    }

    public function get_columns() {
        return array(
            // モバイル時の折りたたみで唯一表示されるプライマリ列。一目で投稿が判別できるよう先頭に配置する。
            'title'      => __( 'AI Generated Title', 'ai-auto-poster' ),
            'created_at' => __( 'Created At', 'ai-auto-poster' ),
            'writer'     => __( 'Provider', 'ai-auto-poster' ),
            'task_name'  => __( 'Task', 'ai-auto-poster' ),
            'status'     => __( 'Post Status', 'ai-auto-poster' ),
            'image'      => __( 'AI Generated Image', 'ai-auto-poster' ),
            'actions'    => __( 'Actions', 'ai-auto-poster' ),
        );
    }

    /**
     * モバイル(782px以下)で折りたたみ時に常時表示される列を指定する。
     * デフォルトの WP_List_Table は最初のテキスト列を採用するが、ここでは明示的に
     * 'title' を指定し、折りたたみ時もタイトルが見える状態にする。
     */
    protected function get_default_primary_column_name() {
        return 'title';
    }

    /**
     * Bug fix: モバイル(<=782px)で WP コアが自動挿入する <button class="toggle-row"> を抑止する。
     *
     * 親クラスのデフォルト実装はプライマリ列に「詳細を表示」トグルボタンを描画し、タップで
     * <tr class="is-expanded"> を付与して非プライマリ列を表示する。しかし本テーブルでは
     * モバイル CSS 側で全列を縦積みカードとして常時表示する設計のため、トグル機構自体が不要。
     *
     * さらに、トグルが残っていると WP コアの ::before ルール
     *   .wp-list-table tr td:not(.column-primary)::before { content: attr(data-colname); position:absolute; left:10px; ... }
     * と padding を 0 にしているプラグイン側 CSS とが衝突し、展開時に「作成日時」「プロバイダ」等の
     * カラム名ラベルがセル内容の上に重なって表示が崩れる(レイアウトが「ぐちゃぐちゃ」になる)。
     * トグルそのものを出さないことで is-expanded が一切付与されず、両方の問題を根本から回避する。
     */
    protected function handle_row_actions( $item, $column_name, $primary ) {
        return '';
    }

    public function get_sortable_columns() {
        // 投稿履歴では並べ替え UI を提供しない。
        return array();
    }

    public function get_bulk_actions() {
        // 投稿履歴は閲覧用途のため、一括削除は提供しない
        return array();
    }

    /**
     * 投稿一覧を取得し、$this->items に格納する。
     *
     * - WP_Query で `_aiap_generated = 1` の投稿を抽出
     * - 並び順: 作成日時の降順固定
     * - ページング: 1ページ20件
     */
    public function prepare_items() {
        $per_page     = 20;
        // 投稿履歴は最新 100 件までに頭打ち。投稿そのものには一切触らず、表示範囲のみ制限する。
        $max_items    = 100;
        $max_pages    = (int) ceil( $max_items / $per_page );
        $current_page = $this->get_pagenum();

        // 投稿履歴では並べ替え UI を提供しないため、作成日時の降順に固定する。
        $orderby_input = 'date';
        $order         = 'DESC';

        $args = array(
            'post_type'      => 'post',
            'post_status'    => array( 'publish', 'draft', 'pending', 'future', 'private' ),
            'posts_per_page' => $per_page,
            'paged'          => $current_page,
            'meta_query'     => array(
                array(
                    'key'     => '_aiap_generated',
                    'value'   => '1',
                    'compare' => '=',
                ),
            ),
            'orderby'        => $orderby_input,
            'order'          => $order,
            'no_found_rows'  => false,
        );

        $query = new WP_Query( $args );

        $items = array();
        foreach ( $query->posts as $post ) {
            $items[] = array(
                'ID'         => $post->ID,
                // タイムスタンプで保持(WPタイムゾーン考慮済み)。$post->post_date文字列は
                // PHPサーバーのTZでstrtotime解釈されてズレる原因になるため使わない。
                'date'       => (int) get_post_timestamp( $post ),
                'status'     => $post->post_status,
                'title'      => $post->post_title,
                'thumb_id'   => (int) get_post_thumbnail_id( $post->ID ),
                'provider'   => (string) get_post_meta( $post->ID, '_aiap_provider', true ),
                'task_id'    => (string) get_post_meta( $post->ID, '_aiap_task_id', true ),
                'is_manual'  => (bool) get_post_meta( $post->ID, '_aiap_manual', true ),
                'edit_url'   => (string) get_edit_post_link( $post->ID, '' ),
                'view_url'   => $post->post_status === 'publish' ? (string) get_permalink( $post->ID ) : '',
            );
        }

        $this->items = $items;

        $columns  = $this->get_columns();
        $hidden   = array();
        $sortable = $this->get_sortable_columns();
        $this->_column_headers = array( $columns, $hidden, $sortable );

        $this->set_pagination_args( array(
            'total_items' => (int) $query->found_posts,
            'per_page'    => $per_page,
            'total_pages' => min( (int) $query->max_num_pages, $max_pages ),
        ) );
    }

    public function column_default( $item, $col ) {
        return isset( $item[ $col ] ) ? esc_html( (string) $item[ $col ] ) : '';
    }

    public function column_created_at( $item ) {
        $ts = isset( $item['date'] ) ? (int) $item['date'] : 0;
        if ( $ts <= 0 ) {
            return '—';
        }
        return esc_html( wp_date( 'Y-m-d H:i:s', $ts ) );
    }

    public function column_writer( $item ) {
        $provider = $item['provider'];
        if ( $provider === '' ) {
            return '—';
        }
        // プロバイダラベル(英字表記。プロバイダ名は両言語共通の固有名詞として扱う)
        $providers = array(
            'claude'     => 'Claude',
            'openai'     => 'OpenAI',
            'gemini'     => 'Gemini',
            'mistral'    => 'Mistral',
            'groq'       => 'Groq',
            'deepseek'   => 'DeepSeek',
            'openrouter' => 'OpenRouter',
        );
        $label = isset( $providers[ $provider ] ) ? $providers[ $provider ] : $provider;
        return esc_html( $label );
    }

    public function column_task_name( $item ) {
        if ( $item['is_manual'] ) {
            return esc_html( __( 'Manual', 'ai-auto-poster' ) );
        }
        $task_id = $item['task_id'];
        if ( $task_id === '' ) {
            return '—';
        }
        if ( class_exists( 'AIAP_Prompts' ) ) {
            $task = AIAP_Prompts::get_by_id( $task_id );
            if ( is_array( $task ) && isset( $task['name'] ) && (string) $task['name'] !== '' ) {
                return esc_html( (string) $task['name'] );
            }
        }
        // タスクが存在しない (削除済み) or 名前未設定 → 短い ID で代替
        /* translators: %s: task ID (e.g. "abc123") */
        return esc_html( sprintf( __( 'Task #%s', 'ai-auto-poster' ), $task_id ) );
    }

    /**
     * Bug fix (audit r9 self-audit, #38): post status のラベル配列が
     * column_status と column_title の両方で重複定義されていたため統合。
     */
    private function get_status_labels() {
        return array(
            'publish' => __( 'Published', 'ai-auto-poster' ),
            'draft'   => __( 'Draft', 'ai-auto-poster' ),
            'future'  => __( 'Scheduled', 'ai-auto-poster' ),
            'pending' => __( 'Pending Review', 'ai-auto-poster' ),
            'private' => __( 'Private', 'ai-auto-poster' ),
        );
    }

    public function column_status( $item ) {
        $status = $item['status'];
        $labels = $this->get_status_labels();
        $label = isset( $labels[ $status ] ) ? $labels[ $status ] : $status;
        return esc_html( $label );
    }

    public function column_title( $item ) {
        $title = $item['title'] !== '' ? $item['title'] : __( '(no title)', 'ai-auto-poster' );
        $title_html = $item['edit_url'] !== ''
            ? sprintf( '<a href="%s">%s</a>', esc_url( $item['edit_url'] ), esc_html( $title ) )
            : esc_html( $title );

        // モバイル(782px以下)折りたたみ時、プライマリ列以外は隠れるため、
        // 主要な補助情報(日時・状態・プロバイダ)をプライマリ列内に重ねて表示する。
        // デスクトップ時はCSSで非表示にして他列との重複を避ける。
        $aux_parts = array();

        $ts = isset( $item['date'] ) ? (int) $item['date'] : 0;
        if ( $ts > 0 ) {
            $aux_parts[] = wp_date( 'Y-m-d H:i', $ts );
        }

        $status_labels = $this->get_status_labels();
        if ( isset( $status_labels[ $item['status'] ] ) ) {
            $aux_parts[] = $status_labels[ $item['status'] ];
        }

        if ( ! empty( $item['provider'] ) ) {
            $providers = array(
                'claude'     => 'Claude',
                'openai'     => 'OpenAI',
                'gemini'     => 'Gemini',
                'mistral'    => 'Mistral',
                'groq'       => 'Groq',
                'deepseek'   => 'DeepSeek',
                'openrouter' => 'OpenRouter',
            );
            $aux_parts[] = isset( $providers[ $item['provider'] ] ) ? $providers[ $item['provider'] ] : $item['provider'];
        }

        $aux_html = '';
        if ( ! empty( $aux_parts ) ) {
            $aux_html = '<div class="aiap-row-aux">' . esc_html( implode( ' · ', $aux_parts ) ) . '</div>';
        }

        return '<strong>' . $title_html . '</strong>' . $aux_html;
    }

    public function column_image( $item ) {
        if ( $item['thumb_id'] <= 0 ) {
            return '<span class="aiap-logs-thumb-placeholder" aria-hidden="true"></span>';
        }
        $img = wp_get_attachment_image(
            $item['thumb_id'],
            array( 60, 60 ),
            false,
            array(
                'class' => 'aiap-logs-thumb',
                'alt'   => '',
            )
        );
        return $img !== '' ? $img : '<span class="aiap-logs-thumb-placeholder" aria-hidden="true"></span>';
    }

    public function column_published( $item ) {
        $status = isset( $item['status'] ) ? (string) $item['status'] : '';
        if ( $status === 'publish' ) {
            return '<span class="aiap-published-state aiap-published-state--publish">' . esc_html__( 'Published', 'ai-auto-poster' ) . '<span class="aiap-state-dot" aria-hidden="true"></span></span>';
        }
        if ( $status === 'draft' ) {
            return '<span class="aiap-published-state aiap-published-state--draft">' . esc_html__( 'Draft', 'ai-auto-poster' ) . '<span class="aiap-state-dot" aria-hidden="true"></span></span>';
        }
        if ( $status === 'future' ) {
            return '<span class="aiap-published-state aiap-published-state--future">' . esc_html__( 'Scheduled', 'ai-auto-poster' ) . '<span class="aiap-state-dot" aria-hidden="true"></span></span>';
        }
        return '—';
    }

    public function column_actions( $item ) {
        $buttons = array();
        $menu_items = array();

        if ( ! empty( $item['view_url'] ) ) {
            $view_label = __( 'View', 'ai-auto-poster' );
            $buttons[] = sprintf(
                '<a href="%s" class="button button-small aiap-action-btn aiap-view-btn" target="_blank" rel="noopener noreferrer" title="%s" aria-label="%s"><span class="dashicons dashicons-visibility" aria-hidden="true"></span><span class="aiap-action-label">%s</span></a>',
                esc_url( $item['view_url'] ),
                esc_attr( $view_label ),
                esc_attr( $view_label ),
                esc_html( $view_label )
            );
            $menu_items[] = sprintf(
                '<a href="%s" target="_blank" rel="noopener noreferrer"><span class="dashicons dashicons-visibility" aria-hidden="true"></span>%s</a>',
                esc_url( $item['view_url'] ),
                esc_html( $view_label )
            );
        }

        if ( ! empty( $item['edit_url'] ) ) {
            $edit_label = __( 'Edit', 'ai-auto-poster' );
            $buttons[] = sprintf(
                '<a href="%s" class="button button-small aiap-action-btn aiap-edit-btn" title="%s" aria-label="%s"><span class="dashicons dashicons-edit" aria-hidden="true"></span><span class="aiap-action-label">%s</span></a>',
                esc_url( $item['edit_url'] ),
                esc_attr( $edit_label ),
                esc_attr( $edit_label ),
                esc_html( $edit_label )
            );
            $menu_items[] = sprintf(
                '<a href="%s"><span class="dashicons dashicons-edit" aria-hidden="true"></span>%s</a>',
                esc_url( $item['edit_url'] ),
                esc_html( $edit_label )
            );
        }

        if ( empty( $buttons ) ) {
            return '—';
        }

        $desktop_actions = '<div class="aiap-action-buttons aiap-action-buttons--desktop">' . implode( '', $buttons ) . '</div>';
        $mobile_actions  = sprintf(
            '<details class="aiap-mobile-action-menu js-aiap-mobile-action-menu"><summary aria-label="%1$s"><span aria-hidden="true">︙</span></summary><div class="aiap-mobile-action-menu__items">%2$s</div></details>',
            esc_attr__( 'Actions', 'ai-auto-poster' ),
            implode( '', $menu_items )
        );

        return $desktop_actions . $mobile_actions;
    }

    public function no_items() {
        echo esc_html( __( 'No AI-generated posts yet.', 'ai-auto-poster' ) );
    }

    /**
     * tablenav の bulkactions と pagination の間に「表示範囲インジケータ」を差し込む。
     *
     * 既存 CSS で .displaying-num (例: "150 items") は非表示にしているため、
     * 代わりに「現在何件目を見ているか」が一目で分かる範囲表示
     * ("Showing 21–40 of 150" / "150件中 21–40を表示") を出力する。
     *
     * - total が 0、または 1 ページに収まる場合は冗長なので非表示にする
     *   (セクション見出しの件数バッジで十分なため)。
     * - 上下両方の tablenav に出る WP 標準の挙動に合わせ、両方で同じ情報を出す
     *   (CSS 側で position に合わせた揃え方を整える)。
     */
    protected function extra_tablenav( $which ) {
        if ( empty( $this->_pagination_args ) ) {
            return;
        }

        $total_items = isset( $this->_pagination_args['total_items'] ) ? (int) $this->_pagination_args['total_items'] : 0;
        $total_pages = isset( $this->_pagination_args['total_pages'] ) ? (int) $this->_pagination_args['total_pages'] : 0;
        $per_page    = isset( $this->_pagination_args['per_page'] ) ? (int) $this->_pagination_args['per_page'] : 0;

        // 1ページに収まる場合は範囲表示しない (セクション見出しの件数で十分)
        if ( $total_items <= 0 || $total_pages <= 1 || $per_page <= 0 ) {
            return;
        }

        $current = (int) $this->get_pagenum();
        if ( $current < 1 ) {
            $current = 1;
        }
        $start = ( $current - 1 ) * $per_page + 1;
        $end   = min( $current * $per_page, $total_items );

        // 上下両方で出るが、CSS 側で揃え方を制御するためクラスで判別できるようにする
        $position_class = ( $which === 'bottom' ) ? 'aiap-tablenav-info--bottom' : 'aiap-tablenav-info--top';

        printf(
            '<div class="aiap-tablenav-info %1$s" aria-live="polite">%2$s</div>',
            esc_attr( $position_class ),
            esc_html( sprintf(
                /* translators: 1: range start (e.g. 21), 2: range end (e.g. 40), 3: total items (e.g. 150) */
                __( 'Showing %1$s–%2$s of %3$s', 'ai-auto-poster' ),
                number_format_i18n( $start ),
                number_format_i18n( $end ),
                number_format_i18n( $total_items )
            ) )
        );
    }
}
