<?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 ) {

            // $item 構築ロジックは AIAP_Poster::build_item_for_post に集約。

            // AIAP_Notifier (= メール通知) も同じ AIAP_Poster::build_item_for_post を呼ぶことで

            // 「投稿履歴と同じ内容」を保証する (= 単一情報源)。

            $item = AIAP_Poster::build_item_for_post( $post );

            if ( is_array( $item ) ) {

                $items[] = $item;

            }

        }



        $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 ),

        ) );

    }



    /**

     * 投稿 ID または WP_Post から、投稿履歴テーブルの 1 行分のデータ配列 ($item) を構築する。

     *

     * prepare_items (管理画面の一覧表示) と AIAP_Notifier (投稿完了通知メール) の両方から呼ばれる

     * 共通処理 (L45/L47)。両者で「投稿履歴と同じ内容」が保証されるよう、必ずこのメソッド経由でデータを取得する。

     *

     * @param WP_Post|int $post_or_id WP_Post オブジェクトまたは post ID

     * @return array|null $item 配列、見つからなければ null

     */



    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 ) {

        // 整形ロジックは AIAP_Poster::format_provider_label に集約 (= メール通知と単一情報源)

        $label = AIAP_Poster::format_provider_label( isset( $item['provider'] ) ? $item['provider'] : '' );

        if ( $label === '—' ) {

            return '—';

        }

        return esc_html( $label );

    }



    public function column_task_name( $item ) {

        // 整形ロジックは AIAP_Poster::format_task_name に集約 (= メール通知と単一情報源)

        return esc_html( AIAP_Poster::format_task_name( $item ) );

    }



    public function column_status( $item ) {

        // 整形ロジックは AIAP_Poster::format_status_label に集約

        return esc_html( AIAP_Poster::format_status_label( isset( $item['status'] ) ? $item['status'] : '' ) );

    }



    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 );

        }



        // ステータス・プロバイダ表示は AIAP_Poster の共通ヘルパで整形 (重複ロジック排除)

        $status_label = AIAP_Poster::format_status_label( isset( $item['status'] ) ? $item['status'] : '' );

        if ( $status_label !== '' ) {

            $aux_parts[] = $status_label;

        }



        $provider_label = AIAP_Poster::format_provider_label( isset( $item['provider'] ) ? $item['provider'] : '' );

        if ( $provider_label !== '' && $provider_label !== '—' ) {

            $aux_parts[] = $provider_label;

        }



        $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 )

            ) )

        );

    }

}

