<?php
/**
 * Arag_Shop — محتوا، رسانه، نظرات فروشگاه آبلیمو
 */
if ( ! defined( 'ABSPATH' ) ) exit;

class Arag_Shop {

    public static function families_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'arag_families';
    }

    public static function reviews_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'arag_reviews';
    }

    public static function settings_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'arag_shop_settings';
    }

    public static function coupons_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'arag_coupons';
    }

    public static function cart_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'arag_cart';
    }

    public static function upload_dir(): string {
        $dir = ( defined( 'ACC_BASE_PATH' ) ? ACC_BASE_PATH : dirname( __DIR__, 2 ) ) . '/uploads/arag';
        if ( ! is_dir( $dir ) ) {
            wp_mkdir_p( $dir );
        }
        return $dir;
    }

    public static function upload_url( string $filename ): string {
        $base = defined( 'ACC_URL' ) ? ACC_URL : '/acc-engine/';
        return rtrim( $base, '/' ) . '/uploads/arag/' . ltrim( $filename, '/' );
    }

    public static function asset_url( string $path ): string {
        $base = defined( 'ACC_URL' ) ? ACC_URL : '/acc-engine/';
        return rtrim( $base, '/' ) . '/assets/img/shop/' . ltrim( $path, '/' );
    }

    public static function abs_url( ?string $url ): string {
        if ( ! $url ) return '';
        if ( str_starts_with( $url, 'http' ) || str_starts_with( $url, '//' ) ) {
            return $url;
        }
        if ( str_starts_with( $url, '/' ) ) {
            return $url;
        }
        $base = defined( 'ACC_URL' ) ? ACC_URL : '/acc-engine/';
        return rtrim( $base, '/' ) . '/' . ltrim( $url, '/' );
    }

    public static function get_settings(): array {
        global $wpdb;
        $t = self::settings_table();
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$t}'" ) !== $t ) {
            return self::default_settings();
        }
        $row = $wpdb->get_row( "SELECT * FROM {$t} WHERE id = 1", ARRAY_A );
        if ( ! $row ) {
            return self::default_settings();
        }
        return self::format_settings( $row );
    }

    public static function default_settings(): array {
        return [
            'brand_name'           => 'آبلیموی شیراز',
            'logo_url'             => '',
            'favicon_url'          => '',
            'primary_color'        => '#1b4332',
            'accent_color'         => '#52b788',
            'support_phone'        => '',
            'support_email'        => '',
            'platform_plan'        => 'enterprise',
            'platform_tagline'     => 'فروشگاه آبلیموی شیراز',
            'hero_eyebrow'         => '',
            'hero_title'           => 'آبلیموی شیراز',
            'hero_subtitle'        => '',
            'hero_video_url'       => '',
            'hero_poster_url'      => self::asset_url( 'hero-lemon.jpg' ),
            'brand_story'          => 'ما باور داریم آبلیمو باید همان‌طور که از لیموی تازه می‌آید، به دست شما برسد — تازگی در مبدأ و خلوص در طعم.',
            'announcements'        => [
                '🚚 ارسال رایگان برای خرید بالای ۵۰۰ هزار تومان',
                '🍋 آبلیموی شیراز از لیموی تازه',
            ],
            'auto_approve_reviews' => true,
        ];
    }

    public static function format_settings( array $row ): array {
        $ann = json_decode( $row['announcements_json'] ?? '[]', true );
        if ( ! is_array( $ann ) ) {
            $ann = [];
        }
        return [
            'brand_name'           => $row['brand_name'] ?? 'آبلیمو',
            'logo_url'             => self::abs_url( $row['logo_url'] ?? '' ),
            'favicon_url'          => self::abs_url( $row['favicon_url'] ?? '' ),
            'primary_color'        => $row['primary_color'] ?? '#1b4332',
            'accent_color'         => $row['accent_color'] ?? '#52b788',
            'support_phone'        => $row['support_phone'] ?? '',
            'support_email'        => $row['support_email'] ?? '',
            'platform_plan'        => $row['platform_plan'] ?? 'enterprise',
            'platform_tagline'     => $row['platform_tagline'] ?? '',
            'hero_eyebrow'         => $row['hero_eyebrow'] ?? '',
            'hero_title'           => $row['hero_title'] ?? '',
            'hero_subtitle'        => $row['hero_subtitle'] ?? '',
            'hero_video_url'       => self::abs_url( $row['hero_video_url'] ?? '' ),
            'hero_poster_url'      => self::abs_url( $row['hero_poster_url'] ?? '' ),
            'brand_story'          => $row['brand_story'] ?? '',
            'announcements'        => array_values( array_filter( $ann ) ),
            'auto_approve_reviews' => ! isset( $row['auto_approve_reviews'] ) || (int) $row['auto_approve_reviews'] === 1,
        ];
    }

    public static function save_settings( array $data ): array {
        global $wpdb;
        $t = self::settings_table();
        $ann = $data['announcements'] ?? null;
        if ( is_array( $ann ) ) {
            $ann = wp_json_encode( array_values( array_filter( array_map( 'sanitize_text_field', $ann ) ) ), JSON_UNESCAPED_UNICODE );
        }
        $payload = [
            'brand_name'           => sanitize_text_field( $data['brand_name'] ?? '' ),
            'logo_url'             => esc_url_raw( $data['logo_url'] ?? '' ),
            'favicon_url'          => esc_url_raw( $data['favicon_url'] ?? '' ),
            'primary_color'        => sanitize_text_field( $data['primary_color'] ?? '#1b4332' ),
            'accent_color'         => sanitize_text_field( $data['accent_color'] ?? '#52b788' ),
            'support_phone'        => sanitize_text_field( $data['support_phone'] ?? '' ),
            'support_email'        => sanitize_email( $data['support_email'] ?? '' ),
            'platform_plan'        => sanitize_key( $data['platform_plan'] ?? 'enterprise' ),
            'platform_tagline'     => sanitize_text_field( $data['platform_tagline'] ?? '' ),
            'hero_eyebrow'         => sanitize_text_field( $data['hero_eyebrow'] ?? '' ),
            'hero_title'           => sanitize_text_field( $data['hero_title'] ?? '' ),
            'hero_subtitle'        => sanitize_textarea_field( $data['hero_subtitle'] ?? '' ),
            'hero_video_url'       => esc_url_raw( $data['hero_video_url'] ?? '' ),
            'hero_poster_url'      => esc_url_raw( $data['hero_poster_url'] ?? '' ),
            'brand_story'          => sanitize_textarea_field( $data['brand_story'] ?? '' ),
            'updated_at'           => current_time( 'mysql' ),
        ];
        if ( $ann !== null ) {
            $payload['announcements_json'] = $ann;
        }
        if ( isset( $data['auto_approve_reviews'] ) ) {
            $payload['auto_approve_reviews'] = ! empty( $data['auto_approve_reviews'] ) ? 1 : 0;
        }
        $exists = (int) $wpdb->get_var( "SELECT id FROM {$t} WHERE id = 1" );
        if ( $exists ) {
            $wpdb->update( $t, $payload, [ 'id' => 1 ] );
        } else {
            $payload['id'] = 1;
            $wpdb->insert( $t, $payload );
        }
        return self::get_settings();
    }

    public static function list_families_public(): array {
        global $wpdb;
        $rows = $wpdb->get_results(
            "SELECT * FROM " . self::families_table() . " WHERE is_active = 1 ORDER BY sort_order ASC, name ASC",
            ARRAY_A
        ) ?: [];
        return array_map( [ __CLASS__, 'format_family_card' ], $rows );
    }

    public static function get_family_by_slug( string $slug ): ?array {
        global $wpdb;
        $row = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM " . self::families_table() . " WHERE slug = %s AND is_active = 1 LIMIT 1",
            $slug
        ), ARRAY_A );
        return $row ? self::format_family_pdp( $row ) : null;
    }

    public static function get_family_by_id( int $id ): ?array {
        global $wpdb;
        $row = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM " . self::families_table() . " WHERE id = %d AND is_active = 1 LIMIT 1",
            $id
        ), ARRAY_A );
        return $row ? self::format_family_pdp( $row ) : null;
    }

    public static function format_family_card( array $row ): array {
        global $wpdb;
        $img = self::abs_url( $row['bottle_image_url'] ?? $row['image_url'] ?? '' );
        $fid = (int) $row['id'];

        $price_row = $wpdb->get_row( $wpdb->prepare(
            "SELECT MIN(p.price) AS min_price, MAX(p.price) AS max_price
             FROM {$wpdb->prefix}arag_packages p
             INNER JOIN {$wpdb->prefix}arag_variants v ON v.id = p.variant_id
             WHERE v.family_id = %d AND p.is_active = 1 AND v.is_active = 1",
            $fid
        ), ARRAY_A );

        $stock = self::family_stock_qty( $fid );

        return [
            'id'          => $fid,
            'name'        => $row['name'],
            'slug'        => $row['slug'],
            'icon'        => $row['icon'] ?? '',
            'tagline'     => $row['tagline'] ?? '',
            'image_url'   => $img,
            'sort_order'  => (int) $row['sort_order'],
            'min_price'   => $price_row ? (float) $price_row['min_price'] : 0,
            'max_price'   => $price_row ? (float) $price_row['max_price'] : 0,
            'stock_qty'   => $stock['qty'],
            'in_stock'    => $stock['in_stock'],
        ];
    }

    public static function family_stock_qty( int $family_id ): array {
        global $wpdb;
        $pre = $wpdb->prefix;
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$pre}inv_stock'" ) !== "{$pre}inv_stock" ) {
            return [ 'qty' => null, 'in_stock' => true ];
        }
        if ( ! file_exists( ACC_PATH . 'includes/helpers/arag-erp.php' ) ) {
            return [ 'qty' => null, 'in_stock' => true ];
        }
        require_once ACC_PATH . 'includes/helpers/arag-erp.php';
        $wh = Arag_Erp::default_warehouse_id();
        if ( $wh <= 0 ) {
            return [ 'qty' => null, 'in_stock' => true ];
        }

        $pkg_ids = $wpdb->get_col( $wpdb->prepare(
            "SELECT p.id FROM {$pre}arag_packages p
             INNER JOIN {$pre}arag_variants v ON v.id = p.variant_id
             WHERE v.family_id = %d AND p.is_active = 1 AND v.is_active = 1",
            $family_id
        ) );
        if ( ! $pkg_ids ) {
            return [ 'qty' => null, 'in_stock' => true ];
        }

        $total = 0.0;
        $has_mapped = false;
        foreach ( $pkg_ids as $pkg_id ) {
            $pid = Arag_Erp::resolve_package_product( (int) $pkg_id );
            if ( $pid <= 0 ) {
                continue;
            }
            $has_mapped = true;
            $total += (float) $wpdb->get_var( $wpdb->prepare(
                "SELECT qty FROM {$pre}inv_stock WHERE product_id = %d AND warehouse_id = %d",
                $pid, $wh
            ) );
        }
        if ( ! $has_mapped ) {
            return [ 'qty' => null, 'in_stock' => true ];
        }
        return [
            'qty'      => (int) floor( $total ),
            'in_stock' => $total > 0,
        ];
    }

    public static function format_family_pdp( array $row ): array {
        global $wpdb;
        $gallery = json_decode( $row['gallery_json'] ?? '[]', true );
        if ( ! is_array( $gallery ) ) $gallery = [];
        $gallery = array_values( array_filter( array_map( [ __CLASS__, 'abs_url' ], $gallery ) ) );

        $bottle = self::abs_url( $row['bottle_image_url'] ?? $row['image_url'] ?? '' );
        if ( $bottle && ! in_array( $bottle, $gallery, true ) ) {
            array_unshift( $gallery, $bottle );
        }
        if ( ! $gallery && $bottle ) {
            $gallery = [ $bottle ];
        }

        $variants = $wpdb->get_results( $wpdb->prepare(
            "SELECT id, name, slug, description, image_url, sort_order
             FROM {$wpdb->prefix}arag_variants
             WHERE family_id = %d AND is_active = 1 ORDER BY sort_order ASC",
            (int) $row['id']
        ), ARRAY_A ) ?: [];

        $variants_out = [];
        foreach ( $variants as $v ) {
            $pkgs = $wpdb->get_results( $wpdb->prepare(
                "SELECT id, label, volume, price, sort_order
                 FROM {$wpdb->prefix}arag_packages
                 WHERE variant_id = %d AND is_active = 1 ORDER BY sort_order ASC, price ASC",
                (int) $v['id']
            ), ARRAY_A ) ?: [];
            $variants_out[] = [
                'id'          => (int) $v['id'],
                'name'        => $v['name'],
                'slug'        => $v['slug'],
                'description' => $v['description'] ?? '',
                'image_url'   => self::abs_url( $v['image_url'] ?? '' ),
                'packages'    => array_map( static function ( $p ) {
                    return [
                        'id'     => (int) $p['id'],
                        'label'  => $p['label'],
                        'volume' => $p['volume'],
                        'price'  => (float) $p['price'],
                    ];
                }, $pkgs ),
            ];
        }

        $reviews = self::list_reviews( (int) $row['id'], 20 );
        $rating  = self::avg_rating( (int) $row['id'] );

        return [
            'id'                => (int) $row['id'],
            'name'              => $row['name'],
            'slug'              => $row['slug'],
            'icon'              => $row['icon'] ?? '',
            'tagline'           => $row['tagline'] ?? '',
            'description_short' => $row['description_short'] ?? '',
            'description_long'  => $row['description_long'] ?? '',
            'bottle_image_url'  => $bottle,
            'gallery'           => $gallery,
            'variants'          => $variants_out,
            'reviews'           => $reviews,
            'rating_avg'        => $rating['avg'],
            'rating_count'    => $rating['count'],
        ];
    }

    public static function list_reviews( int $family_id, int $limit = 20 ): array {
        global $wpdb;
        $t = self::reviews_table();
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$t}'" ) !== $t ) {
            return [];
        }
        $rows = $wpdb->get_results( $wpdb->prepare(
            "SELECT * FROM {$t} WHERE family_id = %d AND is_approved = 1
             ORDER BY created_at DESC LIMIT %d",
            $family_id, $limit
        ), ARRAY_A ) ?: [];
        return array_map( static function ( $r ) {
            return [
                'id'          => (int) $r['id'],
                'author_name' => $r['author_name'],
                'author_city' => $r['author_city'] ?? '',
                'rating'      => (int) $r['rating'],
                'body'        => $r['body'],
                'is_verified' => (bool) $r['is_verified'],
                'created_at'  => $r['created_at'],
            ];
        }, $rows );
    }

    public static function avg_rating( int $family_id ): array {
        global $wpdb;
        $t = self::reviews_table();
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$t}'" ) !== $t ) {
            return [ 'avg' => 0, 'count' => 0 ];
        }
        $row = $wpdb->get_row( $wpdb->prepare(
            "SELECT AVG(rating) AS avg_r, COUNT(*) AS cnt FROM {$t}
             WHERE family_id = %d AND is_approved = 1",
            $family_id
        ), ARRAY_A );
        return [
            'avg'   => $row ? round( (float) $row['avg_r'], 1 ) : 0,
            'count' => $row ? (int) $row['cnt'] : 0,
        ];
    }

    public static function add_review( int $family_id, array $data ): array {
        global $wpdb;
        $t = self::reviews_table();
        $rating = max( 1, min( 5, (int) ( $data['rating'] ?? 5 ) ) );
        $body   = sanitize_textarea_field( $data['body'] ?? '' );
        $name   = sanitize_text_field( $data['author_name'] ?? 'مشتری' );

        if ( strlen( $body ) < 15 ) {
            return [ 'ok' => false, 'message' => 'لطفاً کمی بیشتر درباره تجربه‌تان بنویسید (حداقل ۱۵ کاراکتر).' ];
        }
        if ( strlen( $body ) > 600 ) {
            return [ 'ok' => false, 'message' => 'نظر شما طولانی است؛ لطفاً در ۶۰۰ کاراکتر خلاصه کنید.' ];
        }
        if ( self::review_has_profanity( $body ) || self::review_has_profanity( $name ) ) {
            return [ 'ok' => false, 'message' => 'نظر با احترام ثبت می‌شود. لطفاً بدون توهین یا الفاظ نامناسب بنویسید.' ];
        }

        $settings = self::get_settings();
        $auto_approve = ! empty( $settings['auto_approve_reviews'] );

        $wpdb->insert( $t, [
            'family_id'   => $family_id,
            'author_name' => $name,
            'author_city' => sanitize_text_field( $data['author_city'] ?? '' ),
            'rating'      => $rating,
            'body'        => $body,
            'is_verified' => 0,
            'is_approved' => $auto_approve ? 1 : 0,
            'created_at'  => current_time( 'mysql' ),
        ] );
        $insert_id = (int) $wpdb->insert_id;
        if ( $auto_approve ) {
            $rev = self::list_reviews( $family_id, 1 )[0] ?? null;
        } else {
            $rev = [
                'id'          => $insert_id,
                'author_name' => $name,
                'pending'     => true,
            ];
        }
        if ( ! $rev ) {
            return [ 'ok' => false, 'message' => 'ثبت نظر انجام نشد. دوباره تلاش کنید.' ];
        }
        return [
            'ok'      => true,
            'data'    => $rev,
            'pending' => ! $auto_approve,
            'message' => $auto_approve ? '' : 'نظر شما ثبت شد و پس از تأیید نمایش داده می‌شود.',
        ];
    }

    private static function review_has_profanity( string $text ): bool {
        $text = mb_strtolower( trim( $text ) );
        if ( $text === '' ) {
            return false;
        }
        $patterns = [
            'کس\s*شر',
            'کیر',
            'کون',
            'جنده',
            'حروم',
            'حرومزاده',
            'لاشی',
            'بی\s*شرف',
            'مادر\s*جنده',
            'ننه\s*جنده',
            'خایه',
            'خایه\s*مال',
            'گائید',
            'گایید',
            'سگ\s*پدر',
            'سگ\s*مادر',
            'fuck',
            'shit',
            'bitch',
        ];
        foreach ( $patterns as $p ) {
            if ( preg_match( '/' . $p . '/u', $text ) ) {
                return true;
            }
        }
        return false;
    }

    public static function admin_list_families(): array {
        global $wpdb;
        $rows = $wpdb->get_results(
            "SELECT * FROM " . self::families_table() . " ORDER BY sort_order ASC",
            ARRAY_A
        ) ?: [];
        return array_map( static function ( $r ) {
            return [
                'id'                => (int) $r['id'],
                'name'              => $r['name'],
                'slug'              => $r['slug'],
                'tagline'           => $r['tagline'] ?? '',
                'description_short' => $r['description_short'] ?? '',
                'description_long'  => $r['description_long'] ?? '',
                'bottle_image_url'  => $r['bottle_image_url'] ?? $r['image_url'] ?? '',
                'gallery_json'      => $r['gallery_json'] ?? '[]',
                'is_active'         => (bool) $r['is_active'],
            ];
        }, $rows );
    }

    public static function admin_update_family( int $id, array $data ): bool {
        global $wpdb;
        $gallery = $data['gallery'] ?? null;
        if ( is_array( $gallery ) ) {
            $gallery = wp_json_encode( array_values( $gallery ), JSON_UNESCAPED_UNICODE );
        }
        $payload = array_filter( [
            'tagline'           => isset( $data['tagline'] ) ? sanitize_text_field( $data['tagline'] ) : null,
            'description_short' => isset( $data['description_short'] ) ? sanitize_textarea_field( $data['description_short'] ) : null,
            'description_long'  => isset( $data['description_long'] ) ? sanitize_textarea_field( $data['description_long'] ) : null,
            'bottle_image_url'  => isset( $data['bottle_image_url'] ) ? esc_url_raw( $data['bottle_image_url'] ) : null,
            'image_url'         => isset( $data['bottle_image_url'] ) ? esc_url_raw( $data['bottle_image_url'] ) : null,
            'gallery_json'      => $gallery,
        ], static fn( $v ) => $v !== null );

        if ( ! $payload ) return false;
        return (bool) $wpdb->update( self::families_table(), $payload, [ 'id' => $id ] );
    }

    public static function handle_upload( array $file ): ?array {
        if ( empty( $file['tmp_name'] ) || ! is_uploaded_file( $file['tmp_name'] ) ) {
            if ( ! empty( $file['tmp_name'] ) && is_readable( $file['tmp_name'] ) ) {
                // CLI / test
            } else {
                return null;
            }
        }
        $allowed = [
            'image/jpeg' => 'jpg',
            'image/png'  => 'png',
            'image/webp' => 'webp',
            'video/mp4'  => 'mp4',
            'video/webm' => 'webm',
        ];
        $max_bytes = 8 * 1024 * 1024; // 8MB
        if ( ! empty( $file['size'] ) && (int) $file['size'] > $max_bytes ) {
            return null;
        }
        $mime = mime_content_type( $file['tmp_name'] ) ?: ( $file['type'] ?? '' );
        if ( ! isset( $allowed[ $mime ] ) ) {
            return null;
        }
        // Double-check extension from client name cannot force php/phtml
        $client_ext = strtolower( pathinfo( (string) ( $file['name'] ?? '' ), PATHINFO_EXTENSION ) );
        if ( $client_ext && ! in_array( $client_ext, [ 'jpg', 'jpeg', 'png', 'webp', 'mp4', 'webm' ], true ) ) {
            return null;
        }
        $ext  = $allowed[ $mime ];
        $name = 'arag_' . gmdate( 'Ymd_His' ) . '_' . bin2hex( random_bytes( 4 ) ) . '.' . $ext;
        $dest = self::upload_dir() . '/' . $name;
        if ( ! move_uploaded_file( $file['tmp_name'], $dest ) ) {
            if ( ! @copy( $file['tmp_name'], $dest ) ) {
                return null;
            }
        }
        @chmod( $dest, 0644 );
        return [
            'filename' => $name,
            'url'      => self::upload_url( $name ),
            'mime'     => $mime,
        ];
    }

    /* ── Coupons ── */
    public static function validate_coupon( string $code, float $subtotal ): array {
        global $wpdb;
        $code = strtoupper( trim( $code ) );
        if ( $code === '' ) {
            return [ 'ok' => false, 'message' => 'کد تخفیف خالی است' ];
        }
        $t = self::coupons_table();
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$t}'" ) !== $t ) {
            return self::validate_coupon_fallback( $code, $subtotal );
        }
        $row = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM {$t} WHERE code = %s AND is_active = 1 LIMIT 1", $code
        ), ARRAY_A );
        if ( ! $row ) {
            return [ 'ok' => false, 'message' => 'کد تخفیف نامعتبر است' ];
        }
        if ( $row['expires_at'] && strtotime( $row['expires_at'] ) < time() ) {
            return [ 'ok' => false, 'message' => 'کد تخفیف منقضی شده است' ];
        }
        if ( (float) $row['min_order'] > 0 && $subtotal < (float) $row['min_order'] ) {
            return [ 'ok' => false, 'message' => 'حداقل مبلغ سفارش برای این کد رعایت نشده است' ];
        }
        if ( (int) $row['max_uses'] > 0 && (int) $row['used_count'] >= (int) $row['max_uses'] ) {
            return [ 'ok' => false, 'message' => 'ظرفیت استفاده از این کد تمام شده است' ];
        }
        $discount = self::calc_discount( $row, $subtotal );
        return [
            'ok'       => true,
            'code'     => $row['code'],
            'discount_pct'  => (int) $row['discount_pct'],
            'discount_fixed'=> (float) $row['discount_fixed'],
            'discount_amount' => $discount,
            'min_order' => (float) $row['min_order'],
        ];
    }

    private static function validate_coupon_fallback( string $code, float $subtotal ): array {
        $coupons = [
            'ARAG10'    => [ 'discount_pct' => 10, 'min_order' => 0 ],
            'ARAG15'    => [ 'discount_pct' => 15, 'min_order' => 500000 ],
            'WELCOME20' => [ 'discount_pct' => 20, 'min_order' => 1000000 ],
        ];
        if ( ! isset( $coupons[ $code ] ) ) {
            return [ 'ok' => false, 'message' => 'کد تخفیف نامعتبر است' ];
        }
        $c = $coupons[ $code ];
        if ( $subtotal < $c['min_order'] ) {
            return [ 'ok' => false, 'message' => 'حداقل مبلغ سفارش برای این کد رعایت نشده است' ];
        }
        $discount = round( $subtotal * $c['discount_pct'] / 100 );
        return [
            'ok' => true, 'code' => $code, 'discount_pct' => $c['discount_pct'],
            'discount_fixed' => 0, 'discount_amount' => $discount, 'min_order' => $c['min_order'],
        ];
    }

    public static function calc_discount( array $coupon_row, float $subtotal ): float {
        $pct  = (int) ( $coupon_row['discount_pct'] ?? 0 );
        $fix  = (float) ( $coupon_row['discount_fixed'] ?? 0 );
        $disc = $fix;
        if ( $pct > 0 ) {
            $disc = max( $disc, round( $subtotal * $pct / 100 ) );
        }
        return min( $disc, $subtotal );
    }

    public static function increment_coupon_use( string $code ): void {
        global $wpdb;
        $t = self::coupons_table();
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$t}'" ) !== $t ) {
            return;
        }
        $wpdb->query( $wpdb->prepare(
            "UPDATE {$t} SET used_count = used_count + 1 WHERE code = %s", strtoupper( $code )
        ) );
    }

    public static function admin_list_coupons(): array {
        global $wpdb;
        $t = self::coupons_table();
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$t}'" ) !== $t ) {
            return [];
        }
        return $wpdb->get_results( "SELECT * FROM {$t} ORDER BY id DESC", ARRAY_A ) ?: [];
    }

    public static function admin_save_coupon( array $data, int $id = 0 ): array {
        global $wpdb;
        $t = self::coupons_table();
        $payload = [
            'code'           => strtoupper( sanitize_text_field( $data['code'] ?? '' ) ),
            'discount_pct'   => max( 0, min( 100, (int) ( $data['discount_pct'] ?? 0 ) ) ),
            'discount_fixed' => max( 0, (float) ( $data['discount_fixed'] ?? 0 ) ),
            'min_order'      => max( 0, (float) ( $data['min_order'] ?? 0 ) ),
            'max_uses'       => max( 0, (int) ( $data['max_uses'] ?? 0 ) ),
            'is_active'      => ! empty( $data['is_active'] ) ? 1 : 0,
        ];
        if ( ! empty( $data['expires_at'] ) ) {
            $payload['expires_at'] = sanitize_text_field( $data['expires_at'] );
        } else {
            $payload['expires_at'] = null;
        }
        if ( $id > 0 ) {
            $wpdb->update( $t, $payload, [ 'id' => $id ] );
        } else {
            $wpdb->insert( $t, $payload );
            $id = (int) $wpdb->insert_id;
        }
        return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$t} WHERE id = %d", $id ), ARRAY_A ) ?: $payload;
    }

    public static function admin_delete_coupon( int $id ): bool {
        global $wpdb;
        return (bool) $wpdb->delete( self::coupons_table(), [ 'id' => $id ] );
    }

    /* ── Server cart ── */
    public static function cart_session_key( ?string $from_request = null ): string {
        if ( $from_request && preg_match( '/^[a-zA-Z0-9_-]{16,64}$/', $from_request ) ) {
            return $from_request;
        }
        return bin2hex( random_bytes( 16 ) );
    }

    public static function get_cart( string $session_key, int $user_id = 0 ): array {
        global $wpdb;
        $t = self::cart_table();
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$t}'" ) !== $t ) {
            return [];
        }
        if ( $user_id > 0 ) {
            $row = $wpdb->get_row( $wpdb->prepare(
                "SELECT * FROM {$t} WHERE user_id = %d ORDER BY updated_at DESC LIMIT 1", $user_id
            ), ARRAY_A );
            if ( $row ) {
                return json_decode( $row['items_json'] ?? '[]', true ) ?: [];
            }
        }
        $row = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM {$t} WHERE session_key = %s LIMIT 1", $session_key
        ), ARRAY_A );
        return $row ? ( json_decode( $row['items_json'] ?? '[]', true ) ?: [] ) : [];
    }

    public static function save_cart( string $session_key, array $items, int $user_id = 0 ): array {
        global $wpdb;
        $t = self::cart_table();
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$t}'" ) !== $t ) {
            return $items;
        }
        $json = wp_json_encode( array_values( $items ), JSON_UNESCAPED_UNICODE );
        $existing = null;
        if ( $user_id > 0 ) {
            $existing = $wpdb->get_row( $wpdb->prepare(
                "SELECT id FROM {$t} WHERE user_id = %d LIMIT 1", $user_id
            ), ARRAY_A );
        }
        if ( ! $existing ) {
            $existing = $wpdb->get_row( $wpdb->prepare(
                "SELECT id FROM {$t} WHERE session_key = %s LIMIT 1", $session_key
            ), ARRAY_A );
        }
        $payload = [
            'session_key' => $session_key,
            'user_id'     => $user_id,
            'items_json'  => $json,
            'updated_at'  => current_time( 'mysql' ),
        ];
        if ( $existing ) {
            $wpdb->update( $t, $payload, [ 'id' => (int) $existing['id'] ] );
        } else {
            $wpdb->insert( $t, $payload );
        }
        return $items;
    }

    public static function merge_cart_on_login( string $session_key, int $user_id ): array {
        $guest = self::get_cart( $session_key, 0 );
        $user  = self::get_cart( $session_key, $user_id );
        $merged = $user;
        foreach ( $guest as $gi ) {
            $found = false;
            foreach ( $merged as &$mi ) {
                if ( (int) $mi['package_id'] === (int) $gi['package_id'] ) {
                    $mi['qty'] = (int) $mi['qty'] + (int) $gi['qty'];
                    $found = true;
                    break;
                }
            }
            unset( $mi );
            if ( ! $found ) {
                $merged[] = $gi;
            }
        }
        return self::save_cart( $session_key, $merged, $user_id );
    }

    public static function clear_cart( string $session_key, int $user_id = 0 ): void {
        global $wpdb;
        $t = self::cart_table();
        if ( $user_id > 0 ) {
            $wpdb->delete( $t, [ 'user_id' => $user_id ] );
        }
        $wpdb->delete( $t, [ 'session_key' => $session_key ] );
    }

    /* ── Catalog admin CRUD ── */
    public static function admin_get_catalog( int $family_id ): array {
        global $wpdb;
        $variants = $wpdb->get_results( $wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}arag_variants WHERE family_id = %d ORDER BY sort_order ASC",
            $family_id
        ), ARRAY_A ) ?: [];
        foreach ( $variants as &$v ) {
            $v['packages'] = $wpdb->get_results( $wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}arag_packages WHERE variant_id = %d ORDER BY sort_order ASC",
                (int) $v['id']
            ), ARRAY_A ) ?: [];
        }
        unset( $v );
        return $variants;
    }

    public static function admin_save_variant( int $family_id, array $data, int $id = 0 ): array {
        global $wpdb;
        $t = $wpdb->prefix . 'arag_variants';
        $payload = [
            'family_id'   => $family_id,
            'name'        => sanitize_text_field( $data['name'] ?? '' ),
            'slug'        => sanitize_title( $data['slug'] ?? $data['name'] ?? 'variant' ),
            'description' => sanitize_textarea_field( $data['description'] ?? '' ),
            'image_url'   => esc_url_raw( $data['image_url'] ?? '' ),
            'sort_order'  => (int) ( $data['sort_order'] ?? 0 ),
            'is_active'   => ! isset( $data['is_active'] ) || ! empty( $data['is_active'] ) ? 1 : 0,
        ];
        if ( $id > 0 ) {
            $wpdb->update( $t, $payload, [ 'id' => $id ] );
        } else {
            $wpdb->insert( $t, $payload );
            $id = (int) $wpdb->insert_id;
        }
        return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$t} WHERE id = %d", $id ), ARRAY_A ) ?: $payload;
    }

    public static function admin_delete_variant( int $id ): bool {
        global $wpdb;
        $wpdb->delete( $wpdb->prefix . 'arag_packages', [ 'variant_id' => $id ] );
        return (bool) $wpdb->delete( $wpdb->prefix . 'arag_variants', [ 'id' => $id ] );
    }

    public static function admin_save_package( int $variant_id, array $data, int $id = 0 ): array {
        global $wpdb;
        $t = $wpdb->prefix . 'arag_packages';
        $payload = [
            'variant_id' => $variant_id,
            'label'      => sanitize_text_field( $data['label'] ?? '' ),
            'volume'     => sanitize_text_field( $data['volume'] ?? '' ),
            'price'      => max( 0, (float) ( $data['price'] ?? 0 ) ),
            'sort_order' => (int) ( $data['sort_order'] ?? 0 ),
            'is_active'  => ! isset( $data['is_active'] ) || ! empty( $data['is_active'] ) ? 1 : 0,
        ];
        if ( $id > 0 ) {
            $wpdb->update( $t, $payload, [ 'id' => $id ] );
        } else {
            $wpdb->insert( $t, $payload );
            $id = (int) $wpdb->insert_id;
        }
        return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$t} WHERE id = %d", $id ), ARRAY_A ) ?: $payload;
    }

    public static function admin_delete_package( int $id ): bool {
        global $wpdb;
        return (bool) $wpdb->delete( $wpdb->prefix . 'arag_packages', [ 'id' => $id ] );
    }

    public static function admin_list_reviews( string $status = 'pending', int $limit = 50 ): array {
        global $wpdb;
        $t = self::reviews_table();
        $where = $status === 'pending' ? 'is_approved = 0' : ( $status === 'approved' ? 'is_approved = 1' : '1=1' );
        return $wpdb->get_results(
            "SELECT r.*, f.name AS family_name FROM {$t} r
             LEFT JOIN " . self::families_table() . " f ON f.id = r.family_id
             WHERE {$where} ORDER BY r.created_at DESC LIMIT {$limit}",
            ARRAY_A
        ) ?: [];
    }

    public static function admin_moderate_review( int $id, bool $approve ): bool {
        global $wpdb;
        return (bool) $wpdb->update( self::reviews_table(), [ 'is_approved' => $approve ? 1 : 0 ], [ 'id' => $id ] );
    }

    public static function admin_can(): bool {
        $uid = (int) get_current_user_id();
        if ( $uid <= 0 ) return false;

        if ( function_exists( 'acc_get_current_user' ) ) {
            $user = acc_get_current_user();
            if ( $user && in_array( '*', $user['permissions'] ?? [], true ) ) {
                return true;
            }
        }

        if ( function_exists( 'acl_user_is_super_admin' ) && acl_user_is_super_admin( $uid ) ) {
            return true;
        }
        return function_exists( 'acl_user_can' ) && (
            acl_user_can( $uid, 'system.acl.manage' ) ||
            acl_user_can( $uid, 'shop.manage' ) ||
            acl_user_can( $uid, 'shop.erp' ) ||
            acl_user_can( $uid, 'service.manage' )
        );
    }
}
