<?php
/**
 * Cart Session Manager.
 *
 * Manages the session key that identifies a visitor's cart.
 * Uses a first-party cookie (tc_session) — no PHP sessions involved.
 *
 * The key is a 32-char hex string stored in a cookie.
 * For logged-in customers the same key is used, but the cart row
 * is also tagged with customer_id so it survives cookie loss.
 *
 * @package TitanCart\Modules\Cart
 */

namespace TitanCart\Modules\Cart;

defined( 'ABSPATH' ) || exit;

class CartSession {

    /** Cookie name used to store the session key. */
    const COOKIE_NAME = 'tc_session';

    /** Cookie lifetime in seconds (30 days). */
    const COOKIE_LIFETIME = 30 * DAY_IN_SECONDS;

    /** In-memory cache for the current request. */
    private static ?string $key = null;

    /**
     * Ensure a valid session key cookie exists.
     * Creates and sets a new cookie if none exists.
     *
     * Must be called early (init priority 1) before headers are sent.
     */
    public static function ensure(): void {
        if ( isset( $_COOKIE[ self::COOKIE_NAME ] ) ) {
            $raw = sanitize_text_field( wp_unslash( $_COOKIE[ self::COOKIE_NAME ] ) );
            if ( self::is_valid( $raw ) ) {
                self::$key = $raw;
                return;
            }
        }

        // Generate a fresh key.
        self::$key = self::generate();
        self::set_cookie( self::$key );
    }

    /**
     * Return the current session key, generating one if needed.
     *
     * @return string 32-char hex key.
     */
    public static function get(): string {
        if ( self::$key === null ) {
            self::ensure();
        }
        return self::$key;
    }

    /**
     * Regenerate the session key (e.g. after checkout to prevent fixation).
     *
     * @return string New key.
     */
    public static function regenerate(): string {
        self::$key = self::generate();
        self::set_cookie( self::$key );
        return self::$key;
    }

    /**
     * Clear the session cookie (e.g. on logout / cart clear).
     */
    public static function clear(): void {
        self::$key = null;
        if ( ! headers_sent() ) {
            setcookie(
                self::COOKIE_NAME,
                '',
                time() - YEAR_IN_SECONDS,
                COOKIEPATH,
                COOKIE_DOMAIN,
                is_ssl(),
                true
            );
        }
        unset( $_COOKIE[ self::COOKIE_NAME ] );
    }

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

    private static function generate(): string {
        return bin2hex( random_bytes( 16 ) ); // 32 hex chars.
    }

    private static function is_valid( string $key ): bool {
        return strlen( $key ) === 32 && ctype_xdigit( $key );
    }

    private static function set_cookie( string $key ): void {
        if ( headers_sent() ) {
            return;
        }

        setcookie(
            self::COOKIE_NAME,
            $key,
            [
                'expires'  => time() + self::COOKIE_LIFETIME,
                'path'     => COOKIEPATH,
                'domain'   => COOKIE_DOMAIN,
                'secure'   => is_ssl(),
                'httponly' => true,
                'samesite' => 'Lax',
            ]
        );

        $_COOKIE[ self::COOKIE_NAME ] = $key;
    }
}
