<?php
/**
 * TitanCart — Product Filters REST Controller.
 *
 * Manages storefront product filters: built-in fields (Price, In Stock,
 * Free Shipping, Rating) and attribute-based filters linked to features
 * that have filterable=1.
 *
 * @package TitanCart\REST\Products
 */

namespace TitanCart\REST\Products;

defined( 'ABSPATH' ) || exit;

use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
use WP_Error;

class FiltersController {

    private const NS   = 'titancart/v1';
    private const BASE = 'product-filters';

    /** Built-in product fields available as filter sources. */
    private const BUILT_IN_FIELDS = [
        'price'         => [ 'label' => 'Price',          'group' => 'Product fields', 'default_display' => 'slider' ],
        'in_stock'      => [ 'label' => 'In stock',       'group' => 'Product fields', 'default_display' => 'checkbox' ],
        'free_shipping' => [ 'label' => 'Free shipping',  'group' => 'Product fields', 'default_display' => 'checkbox' ],
        'rating'        => [ 'label' => 'Rating 4+',      'group' => 'Product fields', 'default_display' => 'checkbox' ],
    ];

    public function register_routes(): void {

        // Collection
        \register_rest_route( self::NS, '/' . self::BASE, [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [ $this, 'get_items' ],
                'permission_callback' => [ $this, 'permission' ],
            ],
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [ $this, 'create_item' ],
                'permission_callback' => [ $this, 'permission' ],
            ],
        ] );

        // Single
        \register_rest_route( self::NS, '/' . self::BASE . '/(?P<id>[\d]+)', [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [ $this, 'get_item' ],
                'permission_callback' => [ $this, 'permission' ],
            ],
            [
                'methods'             => WP_REST_Server::EDITABLE,
                'callback'            => [ $this, 'update_item' ],
                'permission_callback' => [ $this, 'permission' ],
            ],
            [
                'methods'             => WP_REST_Server::DELETABLE,
                'callback'            => [ $this, 'delete_item' ],
                'permission_callback' => [ $this, 'permission' ],
            ],
        ] );

        // Categories for a filter
        \register_rest_route( self::NS, '/' . self::BASE . '/(?P<id>[\d]+)/categories', [
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [ $this, 'save_categories' ],
                'permission_callback' => [ $this, 'permission' ],
            ],
        ] );

        // Available filter sources (built-in + filterable attributes)
        \register_rest_route( self::NS, '/' . self::BASE . '/sources', [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [ $this, 'get_sources' ],
                'permission_callback' => [ $this, 'permission' ],
            ],
        ] );
    }

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

    private function db() {
        return \titancart_db();
    }

    private function t( string $name ): string {
        return $this->db()->table( $name );
    }

    private function enrich( array $row ): array {
        $row['filter_id'] = (int) $row['id'];

        // Resolve the filter_by to a human label.
        if ( isset( self::BUILT_IN_FIELDS[ $row['filter_by'] ] ) ) {
            $row['source_label'] = self::BUILT_IN_FIELDS[ $row['filter_by'] ]['label'];
            $row['source_group'] = 'Product fields';
        } elseif ( str_starts_with( $row['filter_by'], 'feature:' ) ) {
            $fid = (int) substr( $row['filter_by'], 8 );
            $fname = $this->db()->getField(
                "SELECT ft.name FROM {$this->t('product_feature_translations')} ft
                 WHERE ft.feature_id = ?i AND ft.language_code = 'en'",
                $fid
            );
            $row['source_label'] = $fname ?: 'Attribute #' . $fid;
            $row['source_group'] = 'Attributes';
            $row['feature_id']   = $fid;
        } else {
            $row['source_label'] = $row['filter_by'];
            $row['source_group'] = 'Unknown';
        }

        // Load categories.
        $row['category_ids'] = array_map( 'intval', $this->db()->getColumn(
            "SELECT category_id FROM {$this->t('product_filter_categories')}
             WHERE filter_id = ?i",
            $row['id']
        ) );

        return $row;
    }

    // ── Handlers ──────────────────────────────────────────────────────────────

    /** GET /product-filters */
    public function get_items( WP_REST_Request $request ): WP_REST_Response {
        $db = $this->db();
        $rows = $db->getArray(
            "SELECT f.id, f.filter_by, f.display_type, f.round_to, f.position, f.start_expanded, f.status,
                    ft.name
             FROM {$this->t('product_filters')} f
             LEFT JOIN {$this->t('product_filter_translations')} ft
                ON ft.filter_id = f.id AND ft.language_code = 'en'
             ORDER BY f.position ASC, f.id ASC"
        );

        return new WP_REST_Response( array_map( [ $this, 'enrich' ], $rows ) );
    }

    /** GET /product-filters/{id} */
    public function get_item( WP_REST_Request $request ): WP_REST_Response {
        $id  = (int) $request->get_param( 'id' );
        $db  = $this->db();
        $row = $db->getRow(
            "SELECT f.id, f.filter_by, f.display_type, f.round_to, f.position, f.start_expanded, f.status,
                    ft.name
             FROM {$this->t('product_filters')} f
             LEFT JOIN {$this->t('product_filter_translations')} ft
                ON ft.filter_id = f.id AND ft.language_code = 'en'
             WHERE f.id = ?i",
            $id
        );
        if ( ! $row ) {
            return new WP_REST_Response( [ 'error' => 'Not found.' ], 404 );
        }
        return new WP_REST_Response( $this->enrich( $row ) );
    }

    /** POST /product-filters */
    public function create_item( WP_REST_Request $request ): WP_REST_Response {
        $body = $request->get_json_params();
        $db   = $this->db();

        $name      = \sanitize_text_field( $body['name'] ?? '' );
        $filter_by = \sanitize_text_field( $body['filter_by'] ?? '' );

        if ( ! $name || ! $filter_by ) {
            return new WP_REST_Response( [ 'error' => 'Name and filter_by required.' ], 400 );
        }

        $filter_id = $db->insert( 'product_filters', [
            'filter_by'      => $filter_by,
            'display_type'   => \sanitize_text_field( $body['display_type'] ?? 'checkbox' ),
            'round_to'       => (float) ( $body['round_to'] ?? 0 ),
            'position'       => (int) ( $body['position'] ?? 0 ),
            'start_expanded' => ! empty( $body['start_expanded'] ) ? 1 : 0,
            'status'         => ( $body['status'] ?? 'active' ) === 'disabled' ? 'disabled' : 'active',
        ] );

        if ( $filter_id ) {
            $db->insert( 'product_filter_translations', [
                'filter_id'     => $filter_id,
                'language_code' => 'en',
                'name'          => $name,
            ] );

            // Save categories if provided.
            $cat_ids = array_map( 'intval', $body['category_ids'] ?? [] );
            foreach ( $cat_ids as $cid ) {
                $db->insert( 'product_filter_categories', [
                    'filter_id'   => $filter_id,
                    'category_id' => $cid,
                ] );
            }
        }

        $row = $db->getRow(
            "SELECT f.id, f.filter_by, f.display_type, f.round_to, f.position, f.start_expanded, f.status, ft.name
             FROM {$this->t('product_filters')} f
             LEFT JOIN {$this->t('product_filter_translations')} ft
                ON ft.filter_id = f.id AND ft.language_code = 'en'
             WHERE f.id = ?i",
            $filter_id
        );

        return new WP_REST_Response( $this->enrich( $row ) );
    }

    /** PUT /product-filters/{id} */
    public function update_item( WP_REST_Request $request ): WP_REST_Response {
        $id   = (int) $request->get_param( 'id' );
        $body = $request->get_json_params();
        $db   = $this->db();

        $update = [];
        if ( isset( $body['filter_by'] ) )    $update['filter_by']    = \sanitize_text_field( $body['filter_by'] );
        if ( isset( $body['display_type'] ) ) $update['display_type'] = \sanitize_text_field( $body['display_type'] );
        if ( isset( $body['round_to'] ) )     $update['round_to']     = (float) $body['round_to'];
        if ( isset( $body['position'] ) )       $update['position']       = (int) $body['position'];
        if ( isset( $body['start_expanded'] ) ) $update['start_expanded'] = ! empty( $body['start_expanded'] ) ? 1 : 0;
        if ( isset( $body['status'] ) )       $update['status']       = $body['status'] === 'disabled' ? 'disabled' : 'active';

        if ( $update ) {
            $db->update( 'product_filters', $update, [ 'id' => $id ] );
        }

        // Translation upsert.
        $name = \sanitize_text_field( $body['name'] ?? '' );
        if ( $name ) {
            $existing = $db->getField(
                "SELECT id FROM {$this->t('product_filter_translations')}
                 WHERE filter_id = ?i AND language_code = 'en'",
                $id
            );
            if ( $existing ) {
                $db->update( 'product_filter_translations', [ 'name' => $name ], [
                    'filter_id' => $id, 'language_code' => 'en',
                ] );
            } else {
                $db->insert( 'product_filter_translations', [
                    'filter_id' => $id, 'language_code' => 'en', 'name' => $name,
                ] );
            }
        }

        // Categories replace.
        if ( isset( $body['category_ids'] ) ) {
            $db->delete( 'product_filter_categories', [ 'filter_id' => $id ] );
            foreach ( array_map( 'intval', $body['category_ids'] ) as $cid ) {
                $db->insert( 'product_filter_categories', [
                    'filter_id' => $id, 'category_id' => $cid,
                ] );
            }
        }

        $row = $db->getRow(
            "SELECT f.id, f.filter_by, f.display_type, f.round_to, f.position, f.start_expanded, f.status, ft.name
             FROM {$this->t('product_filters')} f
             LEFT JOIN {$this->t('product_filter_translations')} ft
                ON ft.filter_id = f.id AND ft.language_code = 'en'
             WHERE f.id = ?i",
            $id
        );

        return new WP_REST_Response( $this->enrich( $row ) );
    }

    /** DELETE /product-filters/{id} */
    public function delete_item( WP_REST_Request $request ): WP_REST_Response {
        $id = (int) $request->get_param( 'id' );
        $db = $this->db();

        $db->delete( 'product_filter_categories',   [ 'filter_id' => $id ] );
        $db->delete( 'product_filter_translations',  [ 'filter_id' => $id ] );
        $db->delete( 'product_filters',              [ 'id'        => $id ] );

        return new WP_REST_Response( [ 'success' => true ] );
    }

    /** POST /product-filters/{id}/categories */
    public function save_categories( WP_REST_Request $request ): WP_REST_Response {
        $id       = (int) $request->get_param( 'id' );
        $body     = $request->get_json_params();
        $cat_ids  = array_map( 'intval', $body['category_ids'] ?? [] );
        $db       = $this->db();

        $db->delete( 'product_filter_categories', [ 'filter_id' => $id ] );
        foreach ( $cat_ids as $cid ) {
            $db->insert( 'product_filter_categories', [
                'filter_id' => $id, 'category_id' => $cid,
            ] );
        }

        return new WP_REST_Response( [ 'success' => true, 'category_ids' => $cat_ids ] );
    }

    /** GET /product-filters/sources — available filter-by sources. */
    public function get_sources( WP_REST_Request $request ): WP_REST_Response {
        $db = $this->db();

        $sources = [];

        // Built-in product fields.
        foreach ( self::BUILT_IN_FIELDS as $key => $field ) {
            $sources[] = [
                'value' => $key,
                'label' => $field['label'],
                'group' => $field['group'],
                'default_display' => $field['default_display'],
            ];
        }

        // Filterable attributes.
        $features = $db->getArray(
            "SELECT f.id, f.type AS feature_type, f.filter_type, ft.name
             FROM {$this->t('product_features')} f
             LEFT JOIN {$this->t('product_feature_translations')} ft
                ON ft.feature_id = f.id AND ft.language_code = 'en'
             WHERE f.filterable = 1 AND f.status = 'active' AND f.type != 'G'
             ORDER BY f.position ASC, f.id ASC"
        );

        foreach ( $features as $feat ) {
            // Set smart default display based on attribute's Display Type:
            // E (Color Swatches) → color, T (Size Pills) → size_pills, else use filter_type or checkbox
            $default = $feat['filter_type'] ?: 'checkbox';
            if ( $feat['feature_type'] === 'E' ) {
                $default = 'color';
            } elseif ( $feat['feature_type'] === 'T' ) {
                $default = 'size_pills';
            }

            $sources[] = [
                'value' => 'feature:' . $feat['id'],
                'label' => $feat['name'] ?: 'Attribute #' . $feat['id'],
                'group' => 'Attributes',
                'default_display' => $default,
            ];
        }

        return new WP_REST_Response( $sources );
    }

    // ── Permission ────────────────────────────────────────────────────────────

    public function permission(): bool|WP_Error {
        if ( \current_user_can( 'manage_options' ) ) {
            return true;
        }
        return new WP_Error( 'tc_rest_forbidden', 'Forbidden.', [ 'status' => 403 ] );
    }
}
