<?php
/**
 * Account REST API Controller.
 *
 * Endpoints:
 *   GET    /titancart/v1/account/profile          Get current customer profile
 *   PUT    /titancart/v1/account/profile          Update profile (name, email, password, phone)
 *
 *   GET    /titancart/v1/account/addresses        List all addresses
 *   POST   /titancart/v1/account/addresses        Create address
 *   PUT    /titancart/v1/account/addresses/{id}   Update address
 *   DELETE /titancart/v1/account/addresses/{id}   Delete address
 *   POST   /titancart/v1/account/addresses/{id}/default  Set as default
 *
 *   GET    /titancart/v1/account/orders           Order history (paginated)
 *   GET    /titancart/v1/account/orders/{id}      Single order detail
 *
 *   DELETE /titancart/v1/account/delete          Soft-delete account + WP user
 *
 * All endpoints require an authenticated WordPress user.
 *
 * @package TitanCart\REST\Accounts
 */

namespace TitanCart\REST\Accounts;

use TitanCart\Modules\Accounts\AccountManager;
use TitanCart\Extensions\GdprExtension;
use WP_REST_Controller;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;

defined( 'ABSPATH' ) || exit;

class AccountController extends WP_REST_Controller {

    protected $namespace = 'titancart/v1';
    protected $rest_base = 'account';

    private AccountManager $manager;

    public function __construct() {
        $this->manager = new AccountManager();
    }

    public function register_routes(): void {

        // ── Profile ───────────────────────────────────────────────────────────
        register_rest_route( $this->namespace, '/' . $this->rest_base . '/profile', [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [ $this, 'get_profile' ],
                'permission_callback' => [ $this, 'is_authenticated' ],
            ],
            [
                'methods'             => WP_REST_Server::EDITABLE,
                'callback'            => [ $this, 'update_profile' ],
                'permission_callback' => [ $this, 'is_authenticated' ],
                'args'                => [
                    'first_name'       => [ 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field' ],
                    'last_name'        => [ 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field' ],
                    'email'            => [ 'type' => 'string', 'format' => 'email' ],
                    'phone'            => [ 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field' ],
                    'current_password' => [ 'type' => 'string' ],
                    'new_password'     => [ 'type' => 'string', 'minLength' => 6 ],
                ],
            ],
        ] );

        // ── Addresses ─────────────────────────────────────────────────────────
        register_rest_route( $this->namespace, '/' . $this->rest_base . '/addresses', [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [ $this, 'get_addresses' ],
                'permission_callback' => [ $this, 'is_authenticated' ],
                'args'                => [
                    'type' => [ 'type' => 'string', 'enum' => [ 'billing', 'shipping' ] ],
                ],
            ],
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [ $this, 'create_address' ],
                'permission_callback' => [ $this, 'is_authenticated' ],
                'args'                => $this->address_args(),
            ],
        ] );

        register_rest_route( $this->namespace, '/' . $this->rest_base . '/addresses/(?P<id>[\d]+)', [
            [
                'methods'             => WP_REST_Server::EDITABLE,
                'callback'            => [ $this, 'update_address' ],
                'permission_callback' => [ $this, 'is_authenticated' ],
                'args'                => array_merge( [ 'id' => [ 'type' => 'integer', 'minimum' => 1 ] ], $this->address_args() ),
            ],
            [
                'methods'             => WP_REST_Server::DELETABLE,
                'callback'            => [ $this, 'delete_address' ],
                'permission_callback' => [ $this, 'is_authenticated' ],
                'args'                => [ 'id' => [ 'type' => 'integer', 'minimum' => 1 ] ],
            ],
        ] );

        register_rest_route( $this->namespace, '/' . $this->rest_base . '/addresses/(?P<id>[\d]+)/default', [
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [ $this, 'set_default_address' ],
                'permission_callback' => [ $this, 'is_authenticated' ],
                'args'                => [ 'id' => [ 'type' => 'integer', 'minimum' => 1 ] ],
            ],
        ] );

        // ── Orders ────────────────────────────────────────────────────────────
        register_rest_route( $this->namespace, '/' . $this->rest_base . '/orders', [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [ $this, 'get_orders' ],
                'permission_callback' => [ $this, 'is_authenticated' ],
                'args'                => [
                    'page'     => [ 'type' => 'integer', 'default' => 1, 'minimum' => 1 ],
                    'per_page' => [ 'type' => 'integer', 'default' => 10, 'minimum' => 1, 'maximum' => 50 ],
                ],
            ],
        ] );

        register_rest_route( $this->namespace, '/' . $this->rest_base . '/orders/(?P<id>[\d]+)', [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [ $this, 'get_order' ],
                'permission_callback' => [ $this, 'is_authenticated' ],
                'args'                => [ 'id' => [ 'type' => 'integer', 'minimum' => 1 ] ],
            ],
        ] );

        // ── Registration (public) ─────────────────────────────────────────────
        // WP.org R1 🅱4: public by design — account creation necessarily
        // precedes authentication (same model as WP's own registration).
        // Schema-validated args, reCAPTCHA surface applies when configured.
        register_rest_route( $this->namespace, '/account/register', [
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [ $this, 'register' ],
                'permission_callback' => '__return_true', // Public by design: guest write-in (account registration) — the caller is not logged in yet; validated/sanitized, reCAPTCHA-gated when configured.
                'args'                => [
                    'email'      => [ 'type' => 'string', 'required' => true, 'format' => 'email' ],
                    'password'   => [ 'type' => 'string', 'required' => true, 'minLength' => 6 ],
                    'first_name' => [ 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field' ],
                    'last_name'  => [ 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field' ],
                    'phone'      => [ 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field' ],
                ],
            ],
        ] );

        // ── Delete account ────────────────────────────────────────────────────
        register_rest_route( $this->namespace, '/' . $this->rest_base . '/delete', [
            [
                'methods'             => WP_REST_Server::DELETABLE,
                'callback'            => [ $this, 'delete_account' ],
                'permission_callback' => [ $this, 'is_authenticated' ],
            ],
        ] );

        // ── Export my data (GDPR data portability) ──────────────────────────────
        register_rest_route( $this->namespace, '/' . $this->rest_base . '/export', [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [ $this, 'export_data' ],
                'permission_callback' => [ $this, 'is_authenticated' ],
            ],
        ] );
    }

    public function get_profile( WP_REST_Request $request ): WP_REST_Response {
        $customer = $this->current_customer();
        if ( ! $customer ) {
            return $this->error_response( 'not_found', __( 'Customer record not found.', 'titancart-lite' ), 404 );
        }
        return new WP_REST_Response( $this->sanitize_profile( $customer ) );
    }

    public function update_profile( WP_REST_Request $request ): WP_REST_Response {
        $customer = $this->current_customer();
        if ( ! $customer ) {
            return $this->error_response( 'not_found', __( 'Customer record not found.', 'titancart-lite' ), 404 );
        }

        $result = $this->manager->update_profile( (int) $customer['id'], $request->get_params() );
        if ( is_wp_error( $result ) ) {
            return $this->error_response( $result->get_error_code(), $result->get_error_message(), 422 );
        }

        $updated = $this->manager->get_profile( (int) $customer['id'] );
        return new WP_REST_Response( $this->sanitize_profile( $updated ?? [] ) );
    }

    public function register( WP_REST_Request $request ): WP_REST_Response {
        $result = $this->manager->register( $request->get_params() );
        if ( is_wp_error( $result ) ) {
            return $this->error_response( $result->get_error_code(), $result->get_error_message(), 422 );
        }
        return new WP_REST_Response( [ 'customer_id' => $result ], 201 );
    }

    // ══════════════════════════════════════════════════════════════════════════
    // HANDLERS — ADDRESSES
    // ══════════════════════════════════════════════════════════════════════════

    public function get_addresses( WP_REST_Request $request ): WP_REST_Response {
        $customer = $this->current_customer();
        if ( ! $customer ) {
            return $this->error_response( 'not_found', __( 'Customer record not found.', 'titancart-lite' ), 404 );
        }

        $type      = $request->get_param( 'type' ) ?: null;
        $addresses = $this->manager->get_addresses( (int) $customer['id'], $type );
        return new WP_REST_Response( $addresses );
    }

    public function create_address( WP_REST_Request $request ): WP_REST_Response {
        $customer = $this->current_customer();
        if ( ! $customer ) {
            return $this->error_response( 'not_found', __( 'Customer record not found.', 'titancart-lite' ), 404 );
        }

        $result = $this->manager->save_address( (int) $customer['id'], $request->get_params() );
        if ( is_wp_error( $result ) ) {
            return $this->error_response( $result->get_error_code(), $result->get_error_message(), 422 );
        }

        return new WP_REST_Response( [ 'id' => $result ], 201 );
    }

    public function update_address( WP_REST_Request $request ): WP_REST_Response {
        $customer = $this->current_customer();
        if ( ! $customer ) {
            return $this->error_response( 'not_found', __( 'Customer record not found.', 'titancart-lite' ), 404 );
        }

        $result = $this->manager->save_address(
            (int) $customer['id'],
            $request->get_params(),
            (int) $request->get_param( 'id' )
        );

        if ( is_wp_error( $result ) ) {
            return $this->error_response( $result->get_error_code(), $result->get_error_message(), 422 );
        }

        return new WP_REST_Response( [ 'id' => $result ] );
    }

    public function delete_address( WP_REST_Request $request ): WP_REST_Response {
        $customer = $this->current_customer();
        if ( ! $customer ) {
            return $this->error_response( 'not_found', __( 'Customer record not found.', 'titancart-lite' ), 404 );
        }

        $result = $this->manager->delete_address(
            (int) $customer['id'],
            (int) $request->get_param( 'id' )
        );

        if ( is_wp_error( $result ) ) {
            return $this->error_response( $result->get_error_code(), $result->get_error_message(), 404 );
        }

        return new WP_REST_Response( null, 204 );
    }

    public function set_default_address( WP_REST_Request $request ): WP_REST_Response {
        $customer = $this->current_customer();
        if ( ! $customer ) {
            return $this->error_response( 'not_found', __( 'Customer record not found.', 'titancart-lite' ), 404 );
        }

        $result = $this->manager->set_default_address(
            (int) $customer['id'],
            (int) $request->get_param( 'id' )
        );

        if ( is_wp_error( $result ) ) {
            return $this->error_response( $result->get_error_code(), $result->get_error_message(), 404 );
        }

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

    // ══════════════════════════════════════════════════════════════════════════
    // HANDLERS — ORDERS
    // ══════════════════════════════════════════════════════════════════════════

    public function get_orders( WP_REST_Request $request ): WP_REST_Response {
        $customer = $this->current_customer();
        if ( ! $customer ) {
            return $this->error_response( 'not_found', __( 'Customer record not found.', 'titancart-lite' ), 404 );
        }

        $result = $this->manager->get_order_history(
            (int) $customer['id'],
            (int) $request->get_param( 'page' ),
            (int) $request->get_param( 'per_page' )
        );

        $response = new WP_REST_Response( $result['items'] );
        $response->header( 'X-TC-Total', (string) $result['total'] );
        $response->header( 'X-TC-Pages', (string) $result['pages'] );
        return $response;
    }

    public function get_order( WP_REST_Request $request ): WP_REST_Response {
        $customer = $this->current_customer();
        if ( ! $customer ) {
            return $this->error_response( 'not_found', __( 'Customer record not found.', 'titancart-lite' ), 404 );
        }

        $db    = titancart_db();
        $order = $db->getRow(
            "SELECT * FROM {$db->table('orders')} WHERE id = ?i AND customer_id = ?i LIMIT 1",
            (int) $request->get_param( 'id' ),
            (int) $customer['id']
        );

        if ( ! $order ) {
            return $this->error_response( 'not_found', __( 'Order not found.', 'titancart-lite' ), 404 );
        }

        // Attach items.
        $order['items'] = $db->getArray(
            "SELECT oi.*, p.price AS current_price
             FROM {$db->table('order_items')} oi
             LEFT JOIN {$db->table('products')} p ON p.id = oi.product_id
             WHERE oi.order_id = ?i",
            (int) $order['id']
        );

        return new WP_REST_Response( $order );
    }

    // ══════════════════════════════════════════════════════════════════════════
    // HANDLER — DELETE ACCOUNT
    // ══════════════════════════════════════════════════════════════════════════

    /**
     * Soft-delete customer record, anonymize data, and delete the WordPress user.
     */
    public function delete_account( WP_REST_Request $request ): WP_REST_Response {
        $customer = $this->current_customer();
        if ( ! $customer ) {
            return $this->error_response( 'not_found', __( 'Customer record not found.', 'titancart-lite' ), 404 );
        }

        // Don't allow admins to self-delete through this endpoint.
        $wp_user_id = (int) $customer['wp_user_id'];
        if ( user_can( $wp_user_id, 'manage_options' ) ) {
            return $this->error_response( 'forbidden', __( 'Administrator accounts cannot be deleted from the storefront.', 'titancart-lite' ), 403 );
        }

        $db          = titancart_db();
        $customer_id = (int) $customer['id'];
        $now         = current_time( 'mysql', true );

        // Gate: deletion must be permitted — either the General Settings
        // "show delete account" option, or the GDPR extension's "allow data
        // deletion" toggle. If neither allows it, refuse. (The storefront also
        // hides the button; this is the matching server-side guard.)
        $deletion_allowed = \TitanCart\Services\SettingsService::bool( 'general', 'customers_show_delete_account', false )
            || GdprExtension::allow_data_deletion();
        if ( ! $deletion_allowed ) {
            return $this->error_response( 'forbidden', __( 'Account deletion is not enabled for this store.', 'titancart-lite' ), 403 );
        }

        // Capture the email BEFORE anonymizing so we can scrub marketing data.
        $email = isset( $customer['email'] ) ? (string) $customer['email'] : '';

        // 1. Soft-delete & anonymize the customer row.
        $db->query(
            "UPDATE {$db->table('customers')}
             SET deleted_at  = ?s,
                 email       = CONCAT('deleted_', id, '@removed.invalid'),
                 first_name  = 'Deleted',
                 last_name   = 'User',
                 phone       = NULL,
                 status      = 'disabled'
             WHERE id = ?i AND deleted_at IS NULL",
            $now,
            $customer_id
        );

        // 2. Remove addresses.
        $db->query(
            "DELETE FROM {$db->table('customer_addresses')} WHERE customer_id = ?i",
            $customer_id
        );

        // 2b. Remove custom (non-system) field values stored in
        //     tc_customer_field_values (S127.C-1). These rows hold PII the
        //     customer entered into admin-defined fields like "Tax ID", and
        //     must follow the same delete-on-request semantics as the rest
        //     of the address/contact data.
        $db->query(
            "DELETE FROM {$db->table('customer_field_values')} WHERE customer_id = ?i",
            $customer_id
        );

        // 3. Remove wishlist items + wishlist.
        $db->query(
            "DELETE wi FROM {$db->table('wishlist_items')} wi
             INNER JOIN {$db->table('wishlists')} w ON w.id = wi.wishlist_id
             WHERE w.customer_id = ?i",
            $customer_id
        );
        $db->query(
            "DELETE FROM {$db->table('wishlists')} WHERE customer_id = ?i",
            $customer_id
        );

        // 4. Clear active cart.
        $db->query(
            "DELETE ci FROM {$db->table('cart_items')} ci
             INNER JOIN {$db->table('carts')} c ON c.id = ci.cart_id
             WHERE c.customer_id = ?i",
            $customer_id
        );
        $db->query(
            "DELETE FROM {$db->table('carts')} WHERE customer_id = ?i",
            $customer_id
        );

        // 4b. Scrub marketing / newsletter data tied to this email.
        if ( $email !== '' ) {
            $sub_id = $db->getField(
                "SELECT id FROM {$db->table('subscribers')} WHERE email = ?s",
                $email
            );
            if ( $sub_id ) {
                $db->query(
                    "DELETE FROM {$db->table('subscriber_list_members')} WHERE subscriber_id = ?i",
                    (int) $sub_id
                );
                $db->query(
                    "DELETE FROM {$db->table('subscribers')} WHERE id = ?i",
                    (int) $sub_id
                );
            }
        }

        // 5. Schedule (or immediately perform) erasure of the order-snapshot
        //    PII. Order financial / line-item data is retained for tax records;
        //    the name/email/address held on past orders is kept for the GDPR
        //    "data retention" window (chargeback + legal-claims hold) and then
        //    anonymized by the daily titancart_gdpr_erasure_tick cron. No orders, or a
        //    last order older than the window → erased immediately.
        $erasure = GdprExtension::schedule_order_pii_erasure( $customer_id );

        // 6. Delete the WordPress user (reassign content to admin user 1).
        require_once ABSPATH . 'wp-admin/includes/user.php';
        wp_delete_user( $wp_user_id, 1 );

        return new WP_REST_Response( [
            'deleted'    => true,
            'erase_mode' => $erasure['mode'],     // 'immediate' | 'scheduled'
            'erase_at'   => $erasure['erase_at'], // gmdate when scheduled, else null
        ] );
    }

    /**
     * GDPR data portability — return everything we hold about the current
     * customer as a structured JSON payload. The storefront turns the response
     * into a downloadable file. Gated on the GDPR extension's "allow data
     * export" toggle.
     */
    public function export_data( WP_REST_Request $request ): WP_REST_Response {
        if ( ! GdprExtension::allow_data_export() ) {
            return $this->error_response( 'forbidden', __( 'Data export is not enabled for this store.', 'titancart-lite' ), 403 );
        }

        $customer = $this->current_customer();
        if ( ! $customer ) {
            return $this->error_response( 'not_found', __( 'Customer record not found.', 'titancart-lite' ), 404 );
        }

        $db  = titancart_db();
        $cid = (int) $customer['id'];

        $profile = [
            'id'              => $cid,
            'email'           => $customer['email'] ?? '',
            'first_name'      => $customer['first_name'] ?? '',
            'last_name'       => $customer['last_name'] ?? '',
            'phone'           => $customer['phone'] ?? null,
            'language'        => $customer['language'] ?? '',
            'currency'        => $customer['currency'] ?? '',
            'total_orders'    => isset( $customer['total_orders'] ) ? (int) $customer['total_orders'] : 0,
            'total_spent'     => $customer['total_spent'] ?? '0',
            'created_at'      => $customer['created_at'] ?? null,
            'last_ordered_at' => $customer['last_ordered_at'] ?? null,
        ];

        $addresses = $db->getArray(
            "SELECT * FROM {$db->table('customer_addresses')} WHERE customer_id = ?i",
            $cid
        );

        $custom_fields = $db->getArray(
            "SELECT field_id, value FROM {$db->table('customer_field_values')} WHERE customer_id = ?i",
            $cid
        );

        $wishlist = $db->getArray(
            "SELECT wi.product_id, wi.created_at
             FROM {$db->table('wishlist_items')} wi
             INNER JOIN {$db->table('wishlists')} w ON w.id = wi.wishlist_id
             WHERE w.customer_id = ?i",
            $cid
        );

        $orders = $db->getArray(
            "SELECT id, order_number, status_id, currency, subtotal, total, created_at,
                    billing_first_name, billing_last_name, billing_company,
                    billing_address_1, billing_address_2, billing_city, billing_state,
                    billing_postcode, billing_country, billing_email, billing_phone,
                    shipping_first_name, shipping_last_name, shipping_company,
                    shipping_address_1, shipping_address_2, shipping_city, shipping_state,
                    shipping_postcode, shipping_country
             FROM {$db->table('orders')} WHERE customer_id = ?i
             ORDER BY id DESC",
            $cid
        );
        foreach ( $orders as &$o ) {
            $o['items'] = $db->getArray(
                "SELECT name, sku, quantity, unit_price, subtotal, total
                 FROM {$db->table('order_items')} WHERE order_id = ?i",
                (int) $o['id']
            );
        }
        unset( $o );

        $payload = [
            'export_generated_at' => gmdate( 'c' ),
            'store'               => home_url( '/' ),
            'profile'             => $profile,
            'addresses'           => $addresses,
            'custom_fields'       => $custom_fields,
            'wishlist'            => $wishlist,
            'orders'              => $orders,
        ];

        return new WP_REST_Response( $payload );
    }

    // ══════════════════════════════════════════════════════════════════════════
    // PERMISSION + HELPERS
    // ══════════════════════════════════════════════════════════════════════════

    /**
     * Permission callback — must be logged in.
     */
    public function is_authenticated( WP_REST_Request $request ): bool {
        return is_user_logged_in();
    }

    /**
     * Resolve tc_customers row for the current WP user.
     */
    private function current_customer(): ?array {
        return $this->manager->get_or_create_current_customer();
    }

    /**
     * Strip sensitive / internal fields before returning profile to client.
     */
    private function sanitize_profile( array $customer ): array {
        unset( $customer['deleted_at'], $customer['notes'] );
        return $customer;
    }

    /**
     * Build a JSON error response.
     */
    private function error_response( string $code, string $message, int $status ): WP_REST_Response {
        return new WP_REST_Response( [ 'code' => $code, 'message' => $message ], $status );
    }

    /**
     * Shared REST arg definitions for address fields.
     */
    private function address_args(): array {
        return [
            'type'       => [ 'type' => 'string', 'enum' => [ 'billing', 'shipping' ] ],
            'first_name' => [ 'type' => 'string', 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ],
            'last_name'  => [ 'type' => 'string', 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ],
            'company'    => [ 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field' ],
            'address_1'  => [ 'type' => 'string', 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ],
            'address_2'  => [ 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field' ],
            'city'       => [ 'type' => 'string', 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ],
            'state'      => [ 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field' ],
            'postcode'   => [ 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field' ],
            'country'    => [ 'type' => 'string', 'required' => true, 'minLength' => 2, 'maxLength' => 2 ],
            'phone'      => [ 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field' ],
        ];
    }
}
