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

/**
 * Custom Post Type registration and admin list table customisation.
 */
class TNC_Flipbook_3D_CPT {

    public static function init() {
        add_action( 'init', array( __CLASS__, 'register' ) );
        add_filter( 'use_block_editor_for_post_type', array( __CLASS__, 'disable_gutenberg' ), 10, 2 );
        add_filter( 'manage_flipbook_posts_columns',       array( __CLASS__, 'columns' ) );
        add_action( 'manage_flipbook_posts_custom_column', array( __CLASS__, 'column_content' ), 10, 2 );
        add_filter( 'manage_edit-flipbook_sortable_columns', array( __CLASS__, 'sortable_columns' ) );

        // Use the plugin's single template for flipbook CPT
        add_filter( 'single_template', array( __CLASS__, 'single_template' ) );

        // Custom admin messages (e.g. "FlipBook published" instead of "Post published")
        add_filter( 'post_updated_messages', array( __CLASS__, 'updated_messages' ) );

    }


    /**
     * Custom admin notice messages for the flipbook CPT.
     */
    public static function updated_messages( $messages ) {
        global $post;

        $permalink = get_permalink( $post->ID ?? 0 );

        // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Reading 'revision' from a WordPress-generated admin link; no state change.
        $messages['tnc_flipbook'] = array(
            0  => '', // Unused. Messages start at index 1.
            1  => sprintf(
                /* translators: %s: View link */
                __( 'FlipBook updated. %s', 'tnc-flipbook-3d-lite' ),
                '<a href="' . esc_url( $permalink ) . '" target="_blank">' . __( 'View FlipBook', 'tnc-flipbook-3d-lite' ) . '</a>'
            ),
            2  => __( 'Custom field updated.', 'tnc-flipbook-3d-lite' ),
            3  => __( 'Custom field deleted.', 'tnc-flipbook-3d-lite' ),
            4  => __( 'FlipBook updated.', 'tnc-flipbook-3d-lite' ),
            5  => isset( $_GET['revision'] )
                /* translators: %s: revision title (e.g. "1 hour ago"). */
                ? sprintf( __( 'FlipBook restored to revision from %s.', 'tnc-flipbook-3d-lite' ), wp_post_revision_title( absint( wp_unslash( $_GET['revision'] ?? 0 ) ), false ) )
                : false,
            6  => sprintf(
                /* translators: %s: View link */
                __( 'FlipBook published. %s', 'tnc-flipbook-3d-lite' ),
                '<a href="' . esc_url( $permalink ) . '" target="_blank">' . __( 'View FlipBook', 'tnc-flipbook-3d-lite' ) . '</a>'
            ),
            7  => __( 'FlipBook saved.', 'tnc-flipbook-3d-lite' ),
            8  => sprintf(
                /* translators: %s: Preview link */
                __( 'FlipBook submitted. %s', 'tnc-flipbook-3d-lite' ),
                '<a href="' . esc_url( add_query_arg( 'preview', 'true', $permalink ) ) . '">' . __( 'Preview FlipBook', 'tnc-flipbook-3d-lite' ) . '</a>'
            ),
            9  => sprintf(
                /* translators: 1: scheduled date, 2: Preview link */
                __( 'FlipBook scheduled for: %1$s. %2$s', 'tnc-flipbook-3d-lite' ),
                '<strong>' . date_i18n( __( 'M j, Y @ G:i', 'tnc-flipbook-3d-lite' ), strtotime( $post->post_date ?? '' ) ) . '</strong>',
                '<a href="' . esc_url( $permalink ) . '">' . __( 'Preview FlipBook', 'tnc-flipbook-3d-lite' ) . '</a>'
            ),
            10 => sprintf(
                /* translators: %s: Preview link */
                __( 'FlipBook draft updated. %s', 'tnc-flipbook-3d-lite' ),
                '<a href="' . esc_url( add_query_arg( 'preview', 'true', $permalink ) ) . '">' . __( 'Preview FlipBook', 'tnc-flipbook-3d-lite' ) . '</a>'
            ),
        );
        // phpcs:enable WordPress.Security.NonceVerification.Recommended

        /**
         * @hook tncfb3d_cpt_messages
         * @param array   $messages Flipbook admin notice messages.
         * @param WP_Post $post     Current post object.
         * @return array
         */
        $messages['tnc_flipbook'] = apply_filters( 'tncfb3d_cpt_messages', $messages['tnc_flipbook'], $post );

        return $messages;
    }

    /**
     * Register the flipbook CPT.
     * Called on init (and also directly from activation hook so rewrite rules flush correctly).
     */
    public static function register() {
        $labels = array(
            'name'               => _x( 'FlipBooks', 'post type general name', 'tnc-flipbook-3d-lite' ),
            'singular_name'      => _x( 'FlipBook', 'post type singular name', 'tnc-flipbook-3d-lite' ),
            'add_new'            => __( 'Add New', 'tnc-flipbook-3d-lite' ),
            'add_new_item'       => __( 'Add New FlipBook', 'tnc-flipbook-3d-lite' ),
            'edit_item'          => __( 'Edit FlipBook', 'tnc-flipbook-3d-lite' ),
            'new_item'           => __( 'New FlipBook', 'tnc-flipbook-3d-lite' ),
            'view_item'          => __( 'View FlipBook', 'tnc-flipbook-3d-lite' ),
            'search_items'       => __( 'Search FlipBooks', 'tnc-flipbook-3d-lite' ),
            'not_found'          => __( 'No FlipBooks found.', 'tnc-flipbook-3d-lite' ),
            'not_found_in_trash' => __( 'No FlipBooks found in Trash.', 'tnc-flipbook-3d-lite' ),
            'all_items'          => __( 'All FlipBooks', 'tnc-flipbook-3d-lite' ),
            'menu_name'          => __( 'TNC FlipBook 3D', 'tnc-flipbook-3d-lite' ),
        );

        $args = array(
            'labels'              => $labels,
            'description'         => __( '3D interactive flipbooks created with TNC FlipBook 3D.', 'tnc-flipbook-3d-lite' ),
            'public'              => true,
            'publicly_queryable'  => true,
            'show_ui'             => true,
            'show_in_menu'        => true,
            'menu_position'       => 11,
            'menu_icon'           => self::menu_icon(),
            'supports'            => array( 'title', 'thumbnail' ),
            'show_in_rest'        => true,               // Required so Gutenberg blocks can query posts
            'rest_base'           => 'flipbooks',
            'capability_type'     => 'post',
            'has_archive'         => false,
            'rewrite'             => array( 'slug' => 'flipbook', 'with_front' => false ),
        );

        /**
         * @hook tncfb3d_cpt_args
         * @param array $args Arguments passed to register_post_type().
         * @return array
         */
        $args = apply_filters( 'tncfb3d_cpt_args', $args );

        register_post_type( TNC_FLIPBOOK_3D_CPT, $args );

        /**
         * @hook tncfb3d_after_register_cpt
         */
        do_action( 'tncfb3d_after_register_cpt' );
    }

    /**
     * Disable the Gutenberg block editor for this CPT (use classic metaboxes instead).
     * show_in_rest remains true so blocks in posts/pages can still query flipbook posts.
     */
    public static function disable_gutenberg( $use_block_editor, $post_type ) {
        if ( TNC_FLIPBOOK_3D_CPT === $post_type ) {
            return false;
        }
        return $use_block_editor;
    }

    // ── List table ────────────────────────────────────────────────────────────

    /**
     * Define custom columns for the flipbook list table.
     */
    public static function columns( $columns ) {
        // Keep cb (checkbox) and title, then insert our columns, then date
        $new = array();
        foreach ( $columns as $key => $label ) {
            if ( 'title' === $key ) {
                $new['thumbnail'] = '';
            }
            $new[ $key ] = $label;
            if ( 'title' === $key ) {
                $new['shortcode']    = __( 'Shortcode', 'tnc-flipbook-3d-lite' );
                $new['source_type']  = __( 'Source', 'tnc-flipbook-3d-lite' );
                $new['page_count']   = __( 'Pages', 'tnc-flipbook-3d-lite' );
            }
        }
        /**
         * @hook tncfb3d_cpt_columns
         * @param array $columns Admin list table columns.
         * @return array
         */
        return apply_filters( 'tncfb3d_cpt_columns', $new );
    }

    /**
     * Output content for each custom column.
     */
    public static function column_content( $column, $post_id ) {
        switch ( $column ) {
            case 'thumbnail':
                $cover_url = function_exists( 'tnc_flipbook_3d_get_cover_url' )
                    ? tnc_flipbook_3d_get_cover_url( $post_id, 'thumbnail' )
                    : '';
                if ( $cover_url ) {
                    echo '<img class="tncfb-list-thumb" src="' . esc_url( $cover_url ) . '" alt="" />';
                } else {
                    echo '<span class="tncfb-list-thumb tncfb-list-thumb--empty" aria-hidden="true">'
                        . '<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>'
                        . '</span>';
                }
                break;

            case 'shortcode':
                $code = '[tnc-flipbook-3d-embed id="' . absint( $post_id ) . '"]';
                echo '<code class="tncfb-copy-code" data-clipboard="' . esc_attr( $code ) . '">'
                    . esc_html( $code )
                    . '</code> '
                    . '<button type="button" class="button button-small tncfb-copy-btn" data-clipboard="' . esc_attr( $code ) . '">'
                    . esc_html__( 'Copy', 'tnc-flipbook-3d-lite' )
                    . '</button>';
                break;

            case 'source_type':
                $type = get_post_meta( $post_id, TNC_FLIPBOOK_3D_PREFIX . 'source_type', true );
                $labels = array(
                    'pdf'       => __( 'Single PDF', 'tnc-flipbook-3d-lite' ),
                    'multi_pdf' => __( 'Multiple PDFs', 'tnc-flipbook-3d-lite' ),
                    'images'    => __( 'Image Gallery', 'tnc-flipbook-3d-lite' ),
                );
                echo isset( $labels[ $type ] ) ? esc_html( $labels[ $type ] ) : '&mdash;';
                break;

            case 'page_count':
                $count = self::resolve_page_count( $post_id );
                echo $count > 0 ? esc_html( $count ) : '&mdash;';
                break;
        }
    }

    /**
     * Register sortable columns.
     */
    public static function sortable_columns( $sortable ) {
        $sortable['page_count'] = 'page_count';
        return $sortable;
    }

    /**
     * Return the page count for a flipbook, computing and caching it if missing.
     */
    public static function resolve_page_count( $post_id ) {
        $p     = TNC_FLIPBOOK_3D_PREFIX;
        $count = (int) get_post_meta( $post_id, $p . 'page_count', true );
        if ( $count > 0 ) {
            return $count;
        }

        $type = get_post_meta( $post_id, $p . 'source_type', true );

        if ( 'images' === $type ) {
            $ids = get_post_meta( $post_id, $p . 'image_ids', true );
            if ( is_array( $ids ) ) {
                $count = count( $ids );
            }
        } elseif ( 'multi_pdf' === $type ) {
            $rows = get_post_meta( $post_id, $p . 'pdf_ids', true );
            if ( is_array( $rows ) ) {
                foreach ( $rows as $row ) {
                    if ( isset( $row['pages'] ) && (int) $row['pages'] > 0 ) {
                        $count += (int) $row['pages'];
                    } elseif ( ! empty( $row['id'] ) ) {
                        $count += self::count_pdf_pages( (int) $row['id'] );
                    }
                }
            }
        } else {
            $aid = (int) get_post_meta( $post_id, $p . 'pdf_id', true );
            if ( $aid ) {
                $count = self::count_pdf_pages( $aid );
            }
        }

        if ( ! $count ) {
            $count = (int) get_post_meta( $post_id, '_tncfb3d_text_page_count', true );
        }

        if ( $count > 0 ) {
            update_post_meta( $post_id, $p . 'page_count', $count );
        }
        return $count;
    }

    /**
     * Count pages in a PDF attachment. Uses smalot/pdfparser if available
     * (Pro), otherwise a lightweight regex on the PDF catalog.
     */
    private static function count_pdf_pages( $attachment_id ) {
        $path = get_attached_file( $attachment_id );
        if ( ! $path || ! file_exists( $path ) ) {
            return 0;
        }
        if ( class_exists( '\\Smalot\\PdfParser\\Parser' ) ) {
            try {
                $parser = new \Smalot\PdfParser\Parser();
                $pdf    = $parser->parseFile( $path );
                $pages  = $pdf->getPages();
                if ( is_array( $pages ) ) {
                    return count( $pages );
                }
            } catch ( \Throwable $e ) {
                // fall through
            }
        }
        // Regex fallback: read the PDF Pages catalog. Cap read size to 2 MB
        // to avoid loading huge files in full just for a count.
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen,WordPress.WP.AlternativeFunctions.file_system_operations_fread,WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Need streaming read of first 2MB for PDF page-count regex; WP_Filesystem has no partial-read API.
        $fh = @fopen( $path, 'rb' );
        if ( ! $fh ) {
            return 0;
        }
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fread
        $contents = @fread( $fh, 2 * 1024 * 1024 );
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
        fclose( $fh );
        if ( $contents && preg_match_all( '/\/Type\s*\/Pages[^>]*?\/Count\s+(\d+)/s', $contents, $m ) ) {
            return (int) max( $m[1] );
        }
        if ( $contents && preg_match_all( '/\/Type\s*\/Page[^s]/', $contents, $m ) ) {
            return count( $m[0] );
        }
        return 0;
    }

    // ── Single template ─────────────────────────────────────────────────────

    /**
     * Use the plugin's own template for the flipbook single post view.
     * This serves the standalone viewer at /flipbook/my-book/ with full
     * CSS/JS isolation - no theme interference.
     */
    public static function single_template( $template ) {
        if ( get_post_type() === TNC_FLIPBOOK_3D_CPT ) {
            $plugin_template = TNC_FLIPBOOK_3D_DIR . 'templates/single-flipbook.php';
            if ( file_exists( $plugin_template ) ) {
                return $plugin_template;
            }
        }
        return $template;
    }

    // ── Helpers ───────────────────────────────────────────────────────────────

    /**
     * Return a base64-encoded SVG for the admin menu icon.
     */
    private static function menu_icon() {
        // Adapted from PDF Viewer for WordPress icon - monochrome for WP admin menu
        $svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 146.63 121.15">'
             . '<path fill="#a7aaad" d="M36.88,77.18C34.94,49.68,41.62,19.45,62.4,0c4.9,3.94,9.81,7.89,14.66,11.89C61.82,22.9,49.42,38.1,42.92,55.83,39.93,62.66,39,70.1,36.88,77.18Z"/>'
             . '<path fill="#a7aaad" d="M27.07,78.7C16.75,68.82,8.07,57.37,0,45.63A75.27,75.27,0,0,0,9.66,50C14.92,59.85,19.92,70,27.07,78.7Z"/>'
             . '<path fill="#a7aaad" d="M13.25,10.57C19.65,13.63,26,16.83,32.32,20c-1.44,10.61-3,21.27-2.53,32-.4,9.55,1.7,18.91,3,28.3C22,58.64,14,35,13.25,10.57Z"/>'
             . '<path fill="#a7aaad" d="M68.45,36.93a122.69,122.69,0,0,1,34.27-19c4.84,5,9.8,9.86,14.7,14.8C126.6,43.3,136.89,52.87,146.63,63q-3.3,2.2-6.56,4.49C126.8,56.1,115.16,43,102.43,31.06a4,4,0,0,0-4.14-.85C80.24,37.63,63.59,49,51.14,64.14c-4.15,5-7.35,10.77-10.81,16.3,2.72-8.13,5.39-16.44,10.3-23.57C55.69,49.52,61.33,42.4,68.45,36.93Z"/>'
             . '<path fill="#a7aaad" d="M63.85,63.32A145.53,145.53,0,0,1,99.14,41.51c12.25,12.12,25.12,23.6,37.72,35.35C121.2,85.06,107,96.22,96.22,110.3a84.29,84.29,0,0,1,29.15-31.85c-.35-1.51-.33-3.28-1.8-4.19-7.53-6.52-15-13.1-22.35-19.85A83.73,83.73,0,0,0,65.6,76.34c-11.06,11.94-19.25,26.32-25.46,41.3l-1.1.83C33.32,106.84,26,95.81,16.41,87,12.14,82.88,7,79.93,2,76.71,10.4,78.81,18.89,81.2,26.17,86c4.62,2.59,8,7,13,9A107.32,107.32,0,0,1,63.85,63.32Z"/>'
             . '<path fill="#a7aaad" d="M73.85,109l-4.27,4.62,4.82,4.45-2.85,3.08-16.36-15.1c2.37-2.57,4.72-5.16,7.1-7.73C69.67,90.32,81.26,101,73.85,109Zm-7.09,2L71,106.39c3.64-4-2.17-9.28-5.8-5.35L61,105.66Z"/>'
             . '<path fill="#a7aaad" d="M91.12,83.27c4.2,3.75,6,10.14.76,15.86L86,105.56,69.59,90.45,75.52,84C80.7,78.42,87,79.61,91.12,83.27ZM85.81,99.76l3.1-3.37c3.44-3.71,2.08-7.69-.65-10.08s-6.53-3.14-9.81.42l-3.11,3.36Z"/>'
             . '<path fill="#a7aaad" d="M101.77,88.42,85.44,73.34,96.29,61.58l3,2.74-8,8.67,4.47,4.12,7.57-8.2,2.85,2.63-7.57,8.21,6.05,5.58Z"/>'
             . '</svg>';
        return 'data:image/svg+xml;base64,' . base64_encode( $svg ); // phpcs:ignore
    }
}
