<?php
/**
 * TitanCart — Product Waitlist REST Controller.
 *
 * Manages back-in-stock notification signups per product.
 * Admin: list, delete, notify subscribers.
 * Public: subscribe (used by storefront "Notify Me" button).
 *
 * @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 WaitlistController {

    private const NS   = 'titancart/v1';

    public function register_routes(): void {

        // Admin: list waitlist for a product
        \register_rest_route( self::NS, '/products/(?P<id>[\d]+)/waitlist', [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [ $this, 'get_items' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
        ] );

        // Admin: delete subscriber(s)
        \register_rest_route( self::NS, '/products/(?P<id>[\d]+)/waitlist/(?P<sub_id>[\d]+)', [
            [
                'methods'             => WP_REST_Server::DELETABLE,
                'callback'            => [ $this, 'delete_item' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
        ] );

        // Admin: bulk delete
        \register_rest_route( self::NS, '/products/(?P<id>[\d]+)/waitlist/bulk-delete', [
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [ $this, 'bulk_delete' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
        ] );

        // Admin: notify all waiting subscribers for a product
        \register_rest_route( self::NS, '/products/(?P<id>[\d]+)/waitlist/notify', [
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [ $this, 'notify_subscribers' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
        ] );

        // Admin: add subscriber manually
        \register_rest_route( self::NS, '/products/(?P<id>[\d]+)/waitlist', [
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [ $this, 'add_subscriber' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
        ] );

        // Public: subscribe to back-in-stock (storefront)
        // WP.org R1 🅱4: public by design — the "Notify Me" button serves guest
        // visitors with no account. Write is insert-only into the caller's own
        // waitlist row (validated email, sanitized fields, validated IP); no
        // reads of other subscribers are exposed on any public route.
        \register_rest_route( self::NS, '/waitlist/subscribe', [
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [ $this, 'public_subscribe' ],
                'permission_callback' => '__return_true', // Public by design: guest write-in (waitlist) — insert-only, validated/sanitized, reCAPTCHA-gated when configured.
            ],
        ] );
    }

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

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

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

    // ── Admin Handlers ────────────────────────────────────────────────────────

    /** GET /products/{id}/waitlist */
    public function get_items( WP_REST_Request $request ): WP_REST_Response {
        $product_id = (int) $request->get_param( 'id' );
        $status     = sanitize_text_field( $request->get_param( 'status' ) ?? '' );
        $search     = sanitize_text_field( $request->get_param( 'search' ) ?? '' );
        $db         = $this->db();

        $where = "WHERE w.product_id = ?i";
        $binds = [ $product_id ];

        if ( $status && in_array( $status, [ 'waiting', 'notified', 'cancelled' ], true ) ) {
            $where .= " AND w.status = ?s";
            $binds[] = $status;
        }
        if ( $search ) {
            $where .= " AND (w.email LIKE ?s OR w.name LIKE ?s)";
            $binds[] = '%' . $search . '%';
            $binds[] = '%' . $search . '%';
        }

        $rows = $db->getArray(
            "SELECT w.*
             FROM {$this->t('product_waitlist')} w
             {$where}
             ORDER BY w.created_at DESC",
            ...$binds
        );

        // Parse attributes_json for display.
        foreach ( $rows as &$row ) {
            $row['attributes'] = json_decode( $row['attributes_json'] ?? '{}', true ) ?: [];
        }
        unset( $row );

        // Stats.
        $stats = [
            'total'     => count( $rows ),
            'waiting'   => 0,
            'notified'  => 0,
            'cancelled' => 0,
        ];
        foreach ( $rows as $r ) {
            if ( isset( $stats[ $r['status'] ] ) ) {
                $stats[ $r['status'] ]++;
            }
        }

        return new WP_REST_Response( [
            'subscribers' => $rows,
            'stats'       => $stats,
        ] );
    }

    /** POST /products/{id}/waitlist — add subscriber manually from admin */
    public function add_subscriber( WP_REST_Request $request ): WP_REST_Response {
        $product_id = (int) $request->get_param( 'id' );
        $body       = $request->get_json_params();
        $db         = $this->db();

        $email = sanitize_email( $body['email'] ?? '' );
        $name  = sanitize_text_field( $body['name'] ?? '' );

        if ( ! $email || ! is_email( $email ) ) {
            return new WP_REST_Response( [ 'error' => 'Valid email is required.' ], 400 );
        }

        // Check duplicate.
        $exists = $db->getField(
            "SELECT id FROM {$this->t('product_waitlist')} WHERE product_id = ?i AND email = ?s",
            $product_id, $email
        );
        if ( $exists ) {
            return new WP_REST_Response( [ 'error' => 'This email is already on the waitlist.' ], 400 );
        }

        $attributes = $body['attributes'] ?? [];

        $id = $db->insert( 'product_waitlist', [
            'product_id'      => $product_id,
            'email'           => $email,
            'name'            => $name,
            'user_id'         => ! empty( $body['user_id'] ) ? (int) $body['user_id'] : null,
            'attributes_json' => ! empty( $attributes ) ? wp_json_encode( $attributes ) : null,
            'status'          => 'waiting',
            'ip_address'      => titancart_client_ip(), // WP.org R1 🅱2: validated capture.
        ] );

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

    /** DELETE /products/{id}/waitlist/{sub_id} */
    public function delete_item( WP_REST_Request $request ): WP_REST_Response {
        $sub_id = (int) $request->get_param( 'sub_id' );
        $this->db()->delete( 'product_waitlist', [ 'id' => $sub_id ] );
        return new WP_REST_Response( [ 'success' => true ] );
    }

    /** POST /products/{id}/waitlist/bulk-delete */
    public function bulk_delete( WP_REST_Request $request ): WP_REST_Response {
        $body = $request->get_json_params();
        $ids  = array_map( 'intval', $body['ids'] ?? [] );
        $db   = $this->db();

        if ( ! empty( $ids ) ) {
            $placeholders = implode( ',', $ids );
            $db->query( "DELETE FROM {$this->t('product_waitlist')} WHERE id IN ({$placeholders})" );
        }

        return new WP_REST_Response( [ 'success' => true, 'deleted' => count( $ids ) ] );
    }

    /** POST /products/{id}/waitlist/notify — notify all waiting subscribers */
    public function notify_subscribers( WP_REST_Request $request ): WP_REST_Response {
        $product_id = (int) $request->get_param( 'id' );
        $db         = $this->db();

        $waiting = $db->getArray(
            "SELECT * FROM {$this->t('product_waitlist')}
             WHERE product_id = ?i AND status = 'waiting'",
            $product_id
        );

        // Get product name for the email.
        $product_name = $db->getField(
            "SELECT pt.name FROM {$this->t('product_translations')} pt
             WHERE pt.product_id = ?i AND pt.language_code = 'en'",
            $product_id
        );

        $notified = 0;
        foreach ( $waiting as $sub ) {
            // Send back-in-stock email.
            $sent = wp_mail(
                $sub['email'],
                sprintf( '%s is back in stock!', $product_name ?: 'Product' ),
                sprintf(
                    "Hi %s,\n\nGreat news! %s is back in stock and ready to order.\n\nVisit our store to get yours before it sells out again.\n\nThank you!",
                    $sub['name'] ?: 'there',
                    $product_name ?: 'The product you were waiting for'
                )
            );

            if ( $sent ) {
                $db->update( 'product_waitlist', [
                    'status'      => 'notified',
                    'notified_at' => current_time( 'mysql' ),
                ], [ 'id' => $sub['id'] ] );
                $notified++;
            }
        }

        return new WP_REST_Response( [
            'success'  => true,
            'notified' => $notified,
            'total'    => count( $waiting ),
        ] );
    }

    // ── Public Handler ────────────────────────────────────────────────────────

    /** POST /waitlist/subscribe — storefront back-in-stock signup */
    public function public_subscribe( WP_REST_Request $request ): WP_REST_Response {
        $body = $request->get_json_params();
        $db   = $this->db();

        $product_id = (int) ( $body['product_id'] ?? 0 );
        $email      = sanitize_email( $body['email'] ?? '' );
        $name       = sanitize_text_field( $body['name'] ?? '' );

        if ( ! $product_id || ! $email || ! is_email( $email ) ) {
            return new WP_REST_Response( [ 'error' => 'Product ID and valid email required.' ], 400 );
        }

        // Check product exists.
        $product_exists = $db->getField(
            "SELECT id FROM {$this->t('products')} WHERE id = ?i AND deleted_at IS NULL",
            $product_id
        );
        if ( ! $product_exists ) {
            return new WP_REST_Response( [ 'error' => 'Product not found.' ], 404 );
        }

        // Check duplicate.
        $exists = $db->getField(
            "SELECT id FROM {$this->t('product_waitlist')} WHERE product_id = ?i AND email = ?s",
            $product_id, $email
        );
        if ( $exists ) {
            return new WP_REST_Response( [ 'message' => 'You are already on the waitlist. We will notify you when it is back in stock.' ] );
        }

        $attributes = $body['attributes'] ?? [];

        $db->insert( 'product_waitlist', [
            'product_id'      => $product_id,
            'email'           => $email,
            'name'            => $name,
            'user_id'         => get_current_user_id() ?: null,
            'attributes_json' => ! empty( $attributes ) ? wp_json_encode( $attributes ) : null,
            'status'          => 'waiting',
            'ip_address'      => titancart_client_ip(), // WP.org R1 🅱2: validated capture.
        ] );

        return new WP_REST_Response( [ 'success' => true, 'message' => 'You will be notified when this product is back in stock.' ] );
    }

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

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