<?php
/**
 * Products Module bootstrapper.
 *
 * Registers REST routes, hooks, and wires up all product/category
 * functionality. Loaded on `titancart_loaded` action.
 *
 * @package TitanCart\Modules\Products
 */

namespace TitanCart\Modules\Products;

use TitanCart\REST\Products\ProductsController;
use TitanCart\REST\Products\CategoriesController;
use TitanCart\REST\Products\FeaturesController;
use TitanCart\REST\Products\FiltersController;
use TitanCart\REST\Products\WaitlistController;
use TitanCart\REST\Products\TabsController;
use TitanCart\REST\Products\TagsController;

defined( 'ABSPATH' ) || exit;

class ProductsModule {

    public function __construct() {
        // REST API routes.
        add_action( 'rest_api_init', [ $this, 'register_routes' ] );

        // Flush slugs on product/category changes.
        add_action( 'titancart_product_saved',   [ $this, 'flush_slugs' ] );
        add_action( 'titancart_category_saved',  [ $this, 'flush_slugs' ] );

        // S309 — when a product is deleted, remove its images from the WP Media
        // Library so they don't pile up (option 1: delete clears Media; no undo).
        add_action( 'titancart_product_deleted', [ $this, 'cleanup_deleted_product_media' ], 10, 1 );
    }

    /**
     * Register REST routes for products and categories.
     */
    public function register_routes(): void {
        ( new ProductsController() )->register_routes();
        ( new CategoriesController() )->register_routes();
        ( new FeaturesController() )->register_routes();
        ( new FiltersController() )->register_routes();
        ( new WaitlistController() )->register_routes();
        ( new TabsController() )->register_routes();
        ( new TagsController() )->register_routes();
    }

    /**
     * Flush rewrite rules when catalog data changes.
     */
    public function flush_slugs(): void {
        delete_option( 'rewrite_rules' );
    }

    /**
     * Remove a deleted product's images from the WP Media Library (S309).
     *
     * Fires on `titancart_product_deleted` (once, for the parent, after the
     * repository has soft-deleted the product AND any variation children). This
     * lives in the WP-integration layer — NOT the portable repository — because
     * it calls wp_delete_attachment(); the repository stays WordPress-free.
     *
     * Covers the parent product plus its variation children, removes their
     * `product_images` rows, then deletes each underlying media attachment ONLY
     * when no remaining product still references it (a shared/reused image is
     * left untouched — same guard as the per-image delete endpoint).
     *
     * @param int $product_id The deleted (parent) product id.
     */
    public function cleanup_deleted_product_media( int $product_id ): void {
        if ( $product_id <= 0 ) {
            return;
        }

        $db    = \titancart_db();
        $t_img = $db->table( 'product_images' );
        $t_lnk = $db->table( 'product_variation_links' );

        // Full set = the product + any variation children (soft-deleted in the
        // same repository call but the action only fires for the parent).
        $ids = [ $product_id ];
        $child_ids = $db->getColumn(
            "SELECT child_id FROM {$t_lnk} WHERE parent_id = ?i",
            $product_id
        );
        if ( ! empty( $child_ids ) ) {
            foreach ( $child_ids as $cid ) {
                $ids[] = (int) $cid;
            }
        }
        $ids = array_values( array_unique( array_map( 'intval', $ids ) ) );

        // Attachment ids owned by these products (captured BEFORE the rows go).
        $attachment_ids = $db->getColumn(
            "SELECT DISTINCT wp_attachment_id FROM {$t_img}
             WHERE product_id IN (?a) AND wp_attachment_id > 0",
            $ids
        );

        // Drop the product_images rows so the unreferenced check below is exact.
        $db->query( "DELETE FROM {$t_img} WHERE product_id IN (?a)", $ids );

        if ( empty( $attachment_ids ) || ! function_exists( 'wp_delete_attachment' ) ) {
            return;
        }

        foreach ( $attachment_ids as $aid ) {
            $aid = (int) $aid;
            if ( $aid <= 0 ) {
                continue;
            }
            // Delete the media file only when no OTHER product still uses it.
            $still_used = (int) $db->getField(
                "SELECT COUNT(*) FROM {$t_img} WHERE wp_attachment_id = ?i",
                $aid
            );
            if ( $still_used === 0 ) {
                \wp_delete_attachment( $aid, true );
            }
        }
    }

    /**
     * Boot the module. Called from Plugin::boot().
     */
    public static function init(): void {
        new self();
    }
}
