<?php
/**
 * GDPR Cookie Banner Extension
 *
 * Injects a cookie consent banner into the storefront.
 * Respects three modes:
 *   - 'none'     → no banner shown
 *   - 'implicit' → browsing = consent, banner is informational
 *   - 'explicit' → must click Accept before non-essential cookies
 *
 * Settings read from tc_settings section = 'gdpr':
 *   gdpr_cookie_consent, cookie_banner_text, cookie_banner_position,
 *   privacy_policy_page, allow_data_export, allow_data_deletion,
 *   checkout_consent, checkout_consent_text
 *
 * @package TitanCart\Extensions
 */

namespace TitanCart\Extensions;

use TitanCart\REST\Extensions\ExtensionsController;

defined( 'ABSPATH' ) || exit;

class GdprExtension {

    public static function init(): void {
        if ( ! ExtensionsController::is_active( 'gdpr' ) ) {
            return;
        }

        // Inject cookie banner on frontend only.
        add_action( 'wp_footer', [ self::class, 'render_cookie_banner' ] );

        // Inject checkout consent checkbox.
        add_action( 'titancart_checkout_before_place_order', [ self::class, 'render_checkout_consent' ] );
    }

    /* ══════════════════════════════════════════════════════════════════════
     * COOKIE CONSENT BANNER
     * ══════════════════════════════════════════════════════════════════════ */

    public static function render_cookie_banner(): void {
        // Don't show in admin.
        if ( is_admin() ) {
            return;
        }

        $s = self::settings();

        // Bail if consent mode is 'none'.
        if ( $s['gdpr_cookie_consent'] === 'none' ) {
            return;
        }

        $position = $s['cookie_banner_position']; // bottom, top, popup
        $text     = $s['cookie_banner_text'];
        $privacy  = $s['privacy_policy_page'];
        $mode     = $s['gdpr_cookie_consent']; // implicit or explicit

        // Overlay only for popup mode
        $overlay = $position === 'popup';

        ?>
        <!-- TitanCart GDPR Cookie Banner -->
        <div id="tc-cookie-banner-wrap" style="display:none; position:fixed; top:0; left:0; right:0; bottom:0; z-index:999999; pointer-events:none;">

            <?php if ( $overlay ) : ?>
                <div id="tc-cookie-overlay"
                     style="position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(0,0,0,0.4); backdrop-filter:blur(4px); -webkit-backdrop-filter:blur(4px); z-index:999999; pointer-events:auto;">
                </div>
            <?php endif; ?>

            <?php if ( $position === 'popup' ) : ?>
                <!-- ── Popup (centred modal) ── -->
                <div id="tc-cookie-banner"
                     style="position:fixed; top:50%; left:50%; transform:translate(-50%,-50%); z-index:1000000; pointer-events:auto;
                            max-width:520px; width:calc(100% - 32px); background:#fff; border-radius:16px;
                            box-shadow:0 25px 60px rgba(0,0,0,.18); padding:32px;
                            font-family:Inter,system-ui,-apple-system,sans-serif;
                            animation:tcBannerSlideIn .35s ease-out;">
                    <?php self::render_banner_content( $text, $privacy, $mode ); ?>
                </div>

            <?php elseif ( $position === 'top' ) : ?>
                <!-- ── Top bar ── -->
                <div id="tc-cookie-banner"
                     style="position:fixed; top:0; left:0; right:0; z-index:1000000; pointer-events:auto;
                            background:#fff; border-bottom:1px solid #e5e7eb;
                            box-shadow:0 4px 24px rgba(0,0,0,.08); padding:16px 24px;
                            font-family:Inter,system-ui,-apple-system,sans-serif;
                            animation:tcBannerSlideDown .35s ease-out;">
                    <div style="max-width:1200px; margin:0 auto;">
                        <?php self::render_banner_content( $text, $privacy, $mode ); ?>
                    </div>
                </div>

            <?php else : ?>
                <!-- ── Bottom bar (default) ── -->
                <div id="tc-cookie-banner"
                     style="position:fixed; bottom:0; left:0; right:0; z-index:1000000; pointer-events:auto;
                            background:#fff; border-top:1px solid #e5e7eb;
                            box-shadow:0 -4px 24px rgba(0,0,0,.08); padding:16px 24px;
                            font-family:Inter,system-ui,-apple-system,sans-serif;
                            animation:tcBannerSlideUp .35s ease-out;">
                    <div style="max-width:1200px; margin:0 auto;">
                        <?php self::render_banner_content( $text, $privacy, $mode ); ?>
                    </div>
                </div>
            <?php endif; ?>

        </div>

        <?php
        // WP.org R2: inline CSS is built as a PHP nowdoc (no output buffering, no
        // markup literals) and attached via wp_add_inline_style on a stub handle
        // (renders on wp_footer@10; print_late_styles fires at 20, so it prints).
        $tc_gdpr_css = <<<'CSS'
            @keyframes tcBannerSlideUp {
                from { opacity:0; transform:translateY(20px); }
                to   { opacity:1; transform:translateY(0); }
            }
            @keyframes tcBannerSlideDown {
                from { opacity:0; transform:translateY(-20px); }
                to   { opacity:1; transform:translateY(0); }
            }
            @keyframes tcBannerSlideIn {
                from { opacity:0; transform:translate(-50%,-50%) scale(0.95); }
                to   { opacity:1; transform:translate(-50%,-50%) scale(1); }
            }
            #tc-cookie-banner-wrap * { box-sizing:border-box; }
CSS;
        wp_register_style( 'titancart-gdpr-inline', false, [], TITANCART_VERSION );
        wp_enqueue_style( 'titancart-gdpr-inline' );
        wp_add_inline_style( 'titancart-gdpr-inline', $tc_gdpr_css );
        ?>

        <?php
        // WP.org R2: NOWDOC + strtr() slot, attached via wp_add_inline_script (footer stub).
        $tc_gdpr_mode = wp_json_encode( $mode );
        $tc_gdpr_js   = <<<'JS'
        (function() {
            'use strict';
            var COOKIE_NAME = 'tc_cookie_consent';
            var COOKIE_DAYS = 365;
            var MODE = %%MODE%%;

            function getCookie(name) {
                var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
                return match ? match[2] : null;
            }

            function setCookie(name, value, days) {
                var d = new Date();
                d.setTime(d.getTime() + days * 86400000);
                document.cookie = name + '=' + value + ';expires=' + d.toUTCString() + ';path=/;SameSite=Lax';
            }

            function hideBanner() {
                var wrap = document.getElementById('tc-cookie-banner-wrap');
                if (wrap) {
                    wrap.style.opacity = '0';
                    wrap.style.transition = 'opacity 0.25s ease';
                    setTimeout(function() { wrap.style.display = 'none'; }, 260);
                }
            }

            // If already consented, don't show.
            if (getCookie(COOKIE_NAME)) return;

            // Show the banner.
            var wrap = document.getElementById('tc-cookie-banner-wrap');
            if (wrap) wrap.style.display = '';

            // Accept button.
            var acceptBtn = document.getElementById('tc-cookie-accept');
            if (acceptBtn) {
                acceptBtn.addEventListener('click', function() {
                    setCookie(COOKIE_NAME, 'accepted', COOKIE_DAYS);
                    hideBanner();
                });
            }

            // Decline button (explicit mode only).
            var declineBtn = document.getElementById('tc-cookie-decline');
            if (declineBtn) {
                declineBtn.addEventListener('click', function() {
                    setCookie(COOKIE_NAME, 'declined', COOKIE_DAYS);
                    hideBanner();
                });
            }

            // Popup mode: clicking overlay also dismisses.
            var overlay = document.getElementById('tc-cookie-overlay');
            if (overlay) {
                overlay.addEventListener('click', function() {
                    setCookie(COOKIE_NAME, 'accepted', COOKIE_DAYS);
                    hideBanner();
                });
            }
        })();
JS;
        $tc_gdpr_js = strtr( $tc_gdpr_js, [ '%%MODE%%' => $tc_gdpr_mode ] );
        wp_register_script( 'titancart-gdpr-inline', false, [], TITANCART_VERSION, true );
        wp_enqueue_script( 'titancart-gdpr-inline' );
        wp_add_inline_script( 'titancart-gdpr-inline', $tc_gdpr_js );
        ?>
        <!-- /TitanCart GDPR Cookie Banner -->
        <?php
    }

    /* ── Shared banner content (text + buttons) ── */
    private static function render_banner_content( string $text, string $privacy, string $mode ): void {
        ?>
        <div style="display:flex; flex-wrap:wrap; align-items:center; gap:16px;">

            <!-- Cookie icon + text -->
            <div style="flex:1 1 300px; display:flex; align-items:flex-start; gap:12px; min-width:0;">
                <span style="font-size:24px; line-height:1; flex-shrink:0;">🍪</span>
                <div style="font-size:14px; line-height:1.6; color:#4b5563;">
                    <?php echo wp_kses_post( $text ); ?>
                    <?php if ( $privacy ) : ?>
                        <a href="<?php echo esc_url( $privacy ); ?>"
                           style="color:#111827; text-decoration:underline; margin-left:4px; white-space:nowrap;"
                           target="_blank" rel="noopener">
                            Privacy Policy
                        </a>
                    <?php endif; ?>
                </div>
            </div>

            <!-- Buttons -->
            <div style="display:flex; gap:10px; flex-shrink:0;">
                <?php if ( $mode === 'explicit' ) : ?>
                    <button id="tc-cookie-decline"
                            style="padding:10px 22px; font-size:14px; font-weight:500; font-family:inherit;
                                   border:1px solid #d1d5db; border-radius:8px; background:#fff;
                                   color:#4b5563; cursor:pointer; transition:all .15s ease; line-height:1;">
                        Decline
                    </button>
                <?php endif; ?>

                <button id="tc-cookie-accept"
                        style="padding:10px 22px; font-size:14px; font-weight:500; font-family:inherit;
                               border:none; border-radius:8px; background:#171717; color:#fff;
                               cursor:pointer; transition:all .15s ease; line-height:1;">
                    Accept<?php echo $mode === 'implicit' ? ' & Close' : ''; ?>
                </button>
            </div>

        </div>
        <?php
    }

    /* ══════════════════════════════════════════════════════════════════════
     * CHECKOUT CONSENT CHECKBOX
     * ══════════════════════════════════════════════════════════════════════ */

    public static function render_checkout_consent(): void {
        $s = self::settings();

        if ( ! $s['checkout_consent'] ) {
            return;
        }

        $label = $s['checkout_consent_text'];
        $privacy = $s['privacy_policy_page'];

        ?>
        <div class="tc-gdpr-consent" style="margin: 16px 0;">
            <label style="display: flex; align-items: flex-start; gap: 8px; cursor: pointer; font-size: 14px; color: #374151;">
                <input type="checkbox" name="gdpr_consent" value="1" required
                       style="margin-top: 3px; accent-color: #000;">
                <span>
                    <?php echo esc_html( $label ); ?>
                    <?php if ( $privacy ) : ?>
                        — <a href="<?php echo esc_url( $privacy ); ?>" target="_blank" rel="noopener"
                              style="text-decoration: underline;">Privacy Policy</a>
                    <?php endif; ?>
                </span>
            </label>
        </div>
        <?php
    }

    /* ══════════════════════════════════════════════════════════════════════
     * HELPER — Check if user has consented
     * ══════════════════════════════════════════════════════════════════════ */

    /**
     * Returns true if the visitor has accepted cookies.
     * Useful for other extensions/modules that want to check before
     * setting non-essential cookies or loading tracking scripts.
     *
     * @return bool
     */
    public static function has_consent(): bool {
        return sanitize_key( wp_unslash( $_COOKIE['tc_cookie_consent'] ?? '' ) ) === 'accepted'; // WP.org R2 item 5: unslash+sanitize at boundary (strict equality was already the gate).
    }

    /* ══════════════════════════════════════════════════════════════════════
     * SETTINGS
     * ══════════════════════════════════════════════════════════════════════ */

    private static function settings(): array {
        $db   = titancart_db();
        $rows = $db->getArray(
            "SELECT `key`, value FROM {$db->table('settings')} WHERE section = ?s",
            'gdpr'
        );

        $vals = [];
        foreach ( $rows as $r ) {
            $vals[ $r['key'] ] = $r['value'];
        }

        return [
            'gdpr_cookie_consent'   => $vals['gdpr_cookie_consent']   ?? 'explicit',
            'cookie_banner_text'    => $vals['cookie_banner_text']    ?? 'We use cookies to improve your experience. By continuing to browse, you agree to our use of cookies.',
            'cookie_banner_position'=> $vals['cookie_banner_position'] ?? 'bottom',
            'privacy_policy_page'   => $vals['privacy_policy_page']   ?? '/privacy-policy',
            'allow_data_export'     => ( $vals['allow_data_export']    ?? '1' ) === '1',
            'allow_data_deletion'   => ( $vals['allow_data_deletion']  ?? '1' ) === '1',
            'data_retention_days'   => max( 0, (int) ( $vals['data_retention_days'] ?? 180 ) ),
            'checkout_consent'      => ( $vals['checkout_consent']     ?? '1' ) === '1',
            'checkout_consent_text' => $vals['checkout_consent_text']  ?? 'I agree to the processing of my personal data',
        ];
    }

    /* ══════════════════════════════════════════════════════════════════════
     * DATA-RIGHTS ACCESSORS (consumed by AccountController + dashboard.php)
     * ══════════════════════════════════════════════════════════════════════ */

    /** Whether the GDPR extension is enabled. */
    public static function is_active(): bool {
        return ExtensionsController::is_active( 'gdpr' );
    }

    /** Whether self-service data export is offered to customers. */
    public static function allow_data_export(): bool {
        return self::is_active() && self::settings()['allow_data_export'];
    }

    /** Whether self-service account deletion is offered to customers. */
    public static function allow_data_deletion(): bool {
        return self::is_active() && self::settings()['allow_data_deletion'];
    }

    /** Retention hold (days) for order-linked PII after a deletion request. */
    public static function data_retention_days(): int {
        return self::settings()['data_retention_days'];
    }

    /* ══════════════════════════════════════════════════════════════════════
     * DEFERRED ERASURE — right to be forgotten with a chargeback/legal hold
     * ══════════════════════════════════════════════════════════════════════ */

    /**
     * Called from the storefront delete-account flow AFTER the customer's
     * non-order PII has been wiped. Decides what happens to the order-snapshot
     * PII (billing/shipping name, email, phone, address held on tc_orders):
     *
     *   - No orders, or last order older than the retention window → anonymize
     *     the order PII immediately.
     *   - Otherwise → stamp tc_customers.erasure_scheduled_at with
     *     (last_order_date + retention window). The daily cron
     *     (run_scheduled_erasures) anonymizes the order PII once it falls due.
     *
     * Financial / line-item data on the order is always retained (tax records).
     *
     * @return array{mode:string,erase_at:?string} mode = 'immediate' | 'scheduled'
     */
    public static function schedule_order_pii_erasure( int $customer_id ): array {
        $db = titancart_db();

        $last = $db->getField(
            "SELECT MAX(created_at) FROM {$db->table('orders')} WHERE customer_id = ?i",
            $customer_id
        );

        // No orders at all → nothing to hold; clear any stale schedule.
        if ( empty( $last ) ) {
            $db->update( 'customers', [ 'erasure_scheduled_at' => null ], [ 'id' => $customer_id ] );
            return [ 'mode' => 'immediate', 'erase_at' => null ];
        }

        $days     = self::data_retention_days();
        $erase_ts = strtotime( $last . ' UTC' ) + ( $days * DAY_IN_SECONDS );

        if ( $erase_ts <= time() ) {
            // Window already elapsed (or a 0-day policy) → erase now.
            self::anonymize_orders_for_customer( $customer_id );
            $db->update( 'customers', [ 'erasure_scheduled_at' => null ], [ 'id' => $customer_id ] );
            return [ 'mode' => 'immediate', 'erase_at' => null ];
        }

        $erase_at = gmdate( 'Y-m-d H:i:s', $erase_ts );
        $db->update( 'customers', [ 'erasure_scheduled_at' => $erase_at ], [ 'id' => $customer_id ] );
        return [ 'mode' => 'scheduled', 'erase_at' => $erase_at ];
    }

    /**
     * Anonymize the personally-identifying columns on every order belonging to
     * a customer. Keeps amounts, dates, line items, state + country (needed for
     * tax records); blanks names, email, phone, address lines, company, city,
     * postcode. Idempotent.
     *
     * @return int Rows affected (best-effort).
     */
    public static function anonymize_orders_for_customer( int $customer_id ): int {
        $db = titancart_db();
        $result = $db->query(
            "UPDATE {$db->table('orders')} SET
                billing_first_name  = 'Deleted',
                billing_last_name   = 'User',
                billing_company     = NULL,
                billing_address_1   = '',
                billing_address_2   = NULL,
                billing_city        = '',
                billing_postcode    = '',
                billing_email       = CONCAT('deleted_order_', id, '@removed.invalid'),
                billing_phone       = NULL,
                shipping_first_name = 'Deleted',
                shipping_last_name  = 'User',
                shipping_company    = NULL,
                shipping_address_1  = '',
                shipping_address_2  = NULL,
                shipping_city       = '',
                shipping_postcode   = '',
                updated_at          = ?s
             WHERE customer_id = ?i",
            titancart_now_utc(),
            $customer_id
        );
        return is_numeric( $result ) ? (int) $result : 0;
    }

    /**
     * Daily cron handler (titancart_gdpr_erasure_tick). Finds every soft-deleted
     * customer whose order-PII retention hold has elapsed, anonymizes their
     * order PII, and clears the schedule. Runs regardless of the GDPR toggle so
     * a pending legal-hold erasure always completes.
     */
    public static function run_scheduled_erasures(): void {
        $db  = titancart_db();
        $now = gmdate( 'Y-m-d H:i:s' );

        $due = $db->getArray(
            "SELECT id FROM {$db->table('customers')}
             WHERE erasure_scheduled_at IS NOT NULL AND erasure_scheduled_at <= ?s
             LIMIT 500",
            $now
        );

        foreach ( $due as $row ) {
            $cid = (int) $row['id'];
            self::anonymize_orders_for_customer( $cid );
            $db->update( 'customers', [ 'erasure_scheduled_at' => null ], [ 'id' => $cid ] );
        }
    }
}
