<?php
/**
 * AccountsModule — bootstrapper for Module 10: Customer Accounts.
 *
 * Registers:
 *   - [titancart_account]     My Account shortcode (login + sub-pages)
 *   - WP hooks for customer sync (user_register, wp_login)
 *   - Rewrite tags/rules for /my-account/ sub-pages
 *   - REST routes via AccountController
 *
 * @package TitanCart\Modules\Accounts
 */

namespace TitanCart\Modules\Accounts;

use TitanCart\Storefront\TemplateLoader;
use TitanCart\REST\Accounts\AccountController;

defined( 'ABSPATH' ) || exit;

class AccountsModule {

    private static AccountManager $manager;

    public static function init(): void {
        $instance       = new self();
        self::$manager  = new AccountManager();

        // Shortcode.
        add_shortcode( 'titancart_account', [ $instance, 'render_account' ] );

        // WP user sync hooks.
        add_action( 'user_register',     [ $instance, 'on_user_register' ], 10, 1 );
        add_action( 'wp_login',          [ $instance, 'on_wp_login' ],      10, 2 );
        add_action( 'delete_user',       [ $instance, 'on_user_deleted' ],  10, 1 );

        // Rewrite rules for pretty /my-account/ URLs.
        add_action( 'init',              [ $instance, 'register_rewrite_rules' ] );
        add_filter( 'query_vars',        [ $instance, 'add_query_vars' ] );

        // Order stats — keep customer aggregate counters in sync. On COMMIT, not
        // placement (KI-04): a declined order must not inflate a customer's order
        // count / total spent. Exactly-once is guaranteed by the commit transient.
        add_action( 'titancart_order_committed', [ $instance, 'on_order_committed' ], 10, 3 );

        // REST routes.
        add_action( 'rest_api_init', [ $instance, 'register_routes' ] );
    }

    // ══════════════════════════════════════════════════════════════════════════
    // SHORTCODE: [titancart_account]
    // ══════════════════════════════════════════════════════════════════════════

    /**
     * Render the My Account area.
     * Shows login/register for guests; the requested sub-page for users.
     *
     * @param  array $atts  Shortcode attributes (unused).
     * @return string  HTML output.
     */
    public function render_account( array $atts = [] ): string {
        ob_start();

        if ( ! is_user_logged_in() ) {
            // Resolve the post-login redirect target. Priority:
            //   1. `?redirect_to=` in the URL — set by `titancart_login_url()` when a
            //      customer was sent here from checkout / wishlist / reviews
            //      / orders. Validated against same-origin via
            //      `wp_validate_redirect()` to prevent open-redirect abuse.
            //   2. Current page URL as a safe last resort. NEVER use
            //      `get_permalink()` here — global `$post` may have been
            //      overwritten by an upstream loop, leaking an article URL.
            $requested = isset( $_GET['redirect_to'] )
                ? esc_url_raw( wp_unslash( (string) $_GET['redirect_to'] ) )
                : '';
            $fallback  = home_url( '/my-account/' );
            $redirect  = $requested
                ? wp_validate_redirect( $requested, $fallback )
                : $fallback;

            // Show login / register form.
            TemplateLoader::get( 'account/login-register.php', [
                'redirect' => $redirect,
            ] );
            return (string) ob_get_clean();
        }

        $customer = self::$manager->get_or_create_current_customer();
        if ( ! $customer ) {
            echo '<p>' . esc_html__( 'Unable to load your account. Please contact support.', 'titancart-lite' ) . '</p>';
            return (string) ob_get_clean();
        }

        // Determine active sub-page.
        $sub_page = get_query_var( 'tc_account_page', '' )
            ?: sanitize_key( $_GET['tc_account_page'] ?? 'dashboard' );

        $allowed = [ 'dashboard', 'orders', 'order-detail', 'addresses', 'profile' ];
        if ( ! in_array( $sub_page, $allowed, true ) ) {
            $sub_page = 'dashboard';
        }

        switch ( $sub_page ) {
            case 'orders':
                $page   = max( 1, absint( wp_unslash( $_GET['paged'] ?? 1 ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- idempotent GET view-state (pagination), see reviewer notes §6.
                $result = self::$manager->get_order_history( (int) $customer['id'], $page, 10 );
                TemplateLoader::get( 'account/orders.php', array_merge( $result, [
                    'customer'     => $customer,
                    'current_page' => $page,
                ] ) );
                break;

            case 'order-detail':
                $order_id = absint( $_GET['tc_order'] ?? 0 );
                $db       = titancart_db();
                $order    = $order_id ? $db->getRow(
                    "SELECT * FROM {$db->table('orders')} WHERE id = ?i AND customer_id = ?i LIMIT 1",
                    $order_id,
                    (int) $customer['id']
                ) : null;
                TemplateLoader::get( 'account/order-detail.php', [
                    'customer' => $customer,
                    'order'    => $order,
                ] );
                break;

            case 'addresses':
                $billing  = self::$manager->get_addresses( (int) $customer['id'], 'billing' );
                $shipping = self::$manager->get_addresses( (int) $customer['id'], 'shipping' );
                TemplateLoader::get( 'account/addresses.php', [
                    'customer'          => $customer,
                    'billing_addresses' => $billing,
                    'shipping_addresses'=> $shipping,
                ] );
                break;

            case 'profile':
                $message = '';
                if ( ! empty( $_POST['tc_update_profile'] ) && check_admin_referer( 'tc_profile_' . get_current_user_id() ) ) {
                    $result = self::$manager->update_profile( (int) $customer['id'], $_POST );
                    $message = is_wp_error( $result )
                        ? $result->get_error_message()
                        : __( 'Profile updated successfully.', 'titancart-lite' );
                    $customer = self::$manager->get_profile( (int) $customer['id'] ) ?: $customer;
                }
                TemplateLoader::get( 'account/profile.php', [
                    'customer' => $customer,
                    'message'  => $message,
                ] );
                break;

            default: // dashboard
                $recent_orders = self::$manager->get_order_history( (int) $customer['id'], 1, 5 );
                TemplateLoader::get( 'account/dashboard.php', [
                    'customer'      => $customer,
                    'recent_orders' => $recent_orders['items'],
                ] );
                break;
        }

        return (string) ob_get_clean();
    }

    // ══════════════════════════════════════════════════════════════════════════
    // WP USER SYNC HOOKS
    // ══════════════════════════════════════════════════════════════════════════

    /**
     * When a WP user registers (via any mechanism), create a tc_customers row.
     *
     * @param  int $wp_user_id
     */
    public function on_user_register( int $wp_user_id ): void {
        // Skip if a record already exists.
        $repo = new CustomerRepository();
        if ( $repo->find_by_wp_user( $wp_user_id ) ) {
            return;
        }

        $user = get_userdata( $wp_user_id );
        if ( ! $user ) {
            return;
        }

        // Note: stale soft-deleted rows holding this email are auto-freed by
        // CustomerRepository::create() before the INSERT runs (see that
        // method's docblock for why). No special handling needed here.
        $repo->create( [
            'wp_user_id' => $wp_user_id,
            'email'      => $user->user_email,
            'first_name' => $user->first_name ?: '',
            'last_name'  => $user->last_name  ?: '',
            'status'     => 'active',
            'created_at' => current_time( 'mysql' ),
            'updated_at' => current_time( 'mysql' ),
        ] );
    }

    /**
     * On login: ensure tc_customers row exists (handles pre-TitanCart users).
     *
     * @param  string    $username
     * @param  \WP_User  $wp_user
     */
    public function on_wp_login( string $username, \WP_User $wp_user ): void {
        $repo = new CustomerRepository();
        if ( ! $repo->find_by_wp_user( $wp_user->ID ) ) {
            $repo->create( [
                'wp_user_id' => $wp_user->ID,
                'email'      => $wp_user->user_email,
                'first_name' => $wp_user->first_name ?: '',
                'last_name'  => $wp_user->last_name  ?: '',
                'status'     => 'active',
                'created_at' => current_time( 'mysql' ),
                'updated_at' => current_time( 'mysql' ),
            ] );
        }
    }

    /**
     * Soft-delete customer record when WP user is deleted.
     *
     * @param  int $wp_user_id
     */
    public function on_user_deleted( int $wp_user_id ): void {
        $repo     = new CustomerRepository();
        $customer = $repo->find_by_wp_user( $wp_user_id );
        if ( $customer ) {
            $repo->soft_delete( (int) $customer['id'] );
        }
    }

    // ══════════════════════════════════════════════════════════════════════════
    // ORDER PLACED HOOK
    // ══════════════════════════════════════════════════════════════════════════

    /**
     * Update customer order stats once an order's payment commits.
     *
     * Reads customer_id + total off the PERSISTED order row by id rather than the
     * event $totals — the async/3DS commit dispatch passes an empty $totals (which
     * would record a $0 spend). Exactly-once per order is guaranteed by the
     * commit transient (see CheckoutManager), so no extra idempotency guard.
     *
     * @param  int   $order_id
     * @param  array $order_data
     * @param  array $totals      Empty on the deferred (Stripe Elements) path.
     */
    public function on_order_committed( int $order_id, array $order_data = [], array $totals = [] ): void {
        if ( $order_id <= 0 ) {
            return;
        }
        $db    = titancart_db();
        $order = $db->getRow(
            "SELECT customer_id, total FROM {$db->table('orders')} WHERE id = ?i LIMIT 1",
            $order_id
        );
        if ( ! $order ) {
            return;
        }
        $customer_id = (int) ( $order['customer_id'] ?? 0 );
        if ( ! $customer_id ) {
            return;
        }
        $repo = new CustomerRepository();
        $repo->increment_order_stats( $customer_id, (float) ( $order['total'] ?? 0 ) );
    }

    // ══════════════════════════════════════════════════════════════════════════
    // REWRITE RULES
    // ══════════════════════════════════════════════════════════════════════════

    /**
     * Register rewrite rules for pretty my-account URLs.
     * e.g. /my-account/orders/  →  ?tc_account_page=orders
     */
    public function register_rewrite_rules(): void {
        add_rewrite_rule( '^my-account/([a-z-]+)/?$', 'index.php?tc_account_page=$matches[1]', 'top' );
    }

    /**
     * Expose tc_account_page to WP's query var system.
     *
     * @param  array $vars
     * @return array
     */
    public function add_query_vars( array $vars ): array {
        $vars[] = 'tc_account_page';
        return $vars;
    }

    // ══════════════════════════════════════════════════════════════════════════
    // REST ROUTES
    // ══════════════════════════════════════════════════════════════════════════

    public function register_routes(): void {
        ( new AccountController() )->register_routes();
        ( new \TitanCart\REST\CustomersController() )->register_routes();
    }
}
