<?php

/**
 * Schema 2025 Types
 *
 * Provides definitions and generators for Schema.org v16+ types introduced in 2024-2025.
 * Includes new types and enhanced properties for existing types.
 *
 * @package ProRank\SEO\Core\Schema
 * @since   2.1.0
 * @see     https://schema.org/version/16.0/
 */

declare(strict_types=1);

namespace ProRank\SEO\Core\Schema;

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}


/**
 * Schema2025Types class
 *
 * Handles generation of 2025 schema types and enhancements
 */


class Schema2025Types {

    /**
     * Generate DiscussionForumPosting schema
     *
     * New in Schema.org v16 for forum posts and community discussions
     *
     * @param \WP_Post $post The post object.
     * @param array    $config Configuration options.
     * @return array Schema data.
     */
    public function generate_discussion_forum_posting($post, $config = []): array {
        $schema = [
            '@context' => 'https://schema.org',
            '@type' => 'DiscussionForumPosting',
            'headline' => get_the_title($post),
            'url' => get_permalink($post),
            'datePublished' => get_the_date('c', $post),
            'dateModified' => get_the_modified_date('c', $post),
            'author' => $this->get_author_person($post),
        ];

        // Add text content
        if (!empty($post->post_content)) {
            $schema['text'] = wp_strip_all_tags($post->post_content);
        }

        // Add interaction statistics (2025 enhancement)
        $comment_count = (int) $post->comment_count;
        if ($comment_count > 0) {
            $schema['interactionStatistic'] = [
                [
                    '@type' => 'InteractionCounter',
                    'interactionType' => 'https://schema.org/CommentAction',
                    'userInteractionCount' => $comment_count
                ],
                [
                    '@type' => 'InteractionCounter',
                    'interactionType' => 'https://schema.org/ShareAction',
                    'userInteractionCount' => $this->get_share_count($post->ID)
                ]
            ];
        }

        // Add discussion forum container if available
        if (!empty($config['forumUrl'])) {
            $schema['isPartOf'] = [
                '@type' => 'WebPage',
                'url' => $config['forumUrl']
            ];
        }

        // Add upvote/downvote counts if available (from meta)
        $upvotes = get_post_meta($post->ID, '_forum_upvotes', true);
        $downvotes = get_post_meta($post->ID, '_forum_downvotes', true);

        if ($upvotes) {
            $schema['upvoteCount'] = (int) $upvotes;
        }

        if ($downvotes) {
            $schema['downvoteCount'] = (int) $downvotes;
        }

        return $schema;
    }

    /**
     * Generate ProfilePage schema
     *
     * New in Schema.org v16 for author/user profile pages
     *
     * @param int   $user_id The user ID.
     * @param array $config Configuration options.
     * @return array Schema data.
     */
    public function generate_profile_page($user_id, $config = []): array {
        $user = get_userdata($user_id);
        if (!$user) {
            return [];
        }

        $schema = [
            '@context' => 'https://schema.org',
            '@type' => 'ProfilePage',
            'mainEntity' => [
                '@type' => 'Person',
                'name' => $user->display_name,
                'identifier' => $user->user_login,
            ],
            'url' => get_author_posts_url($user_id),
            'dateCreated' => get_date_from_gmt($user->user_registered, 'c'),
            'dateModified' => current_time('c')
        ];

        // Add person details
        if (!empty($user->description)) {
            $schema['mainEntity']['description'] = $user->description;
        }

        if (!empty($user->user_url)) {
            $schema['mainEntity']['url'] = $user->user_url;
        }

        // Add avatar image
        $avatar_url = get_avatar_url($user_id, ['size' => 512]);
        if ($avatar_url) {
            $schema['mainEntity']['image'] = [
                '@type' => 'ImageObject',
                'url' => $avatar_url,
                'width' => 512,
                'height' => 512
            ];
        }

        // Add social media profiles (2025 enhancement)
        $social_profiles = [];
        $social_networks = ['facebook', 'twitter', 'linkedin', 'instagram', 'youtube', 'github'];

        foreach ($social_networks as $network) {
            $url = get_user_meta($user_id, $network, true);
            if ($url) {
                $social_profiles[] = $url;
            }
        }

        if (!empty($social_profiles)) {
            $schema['mainEntity']['sameAs'] = $social_profiles;
        }

        // Add job title if available
        $job_title = get_user_meta($user_id, 'job_title', true);
        if ($job_title) {
            $schema['mainEntity']['jobTitle'] = $job_title;
        }

        // Add affiliation if available
        $affiliation = get_user_meta($user_id, 'affiliation', true);
        if ($affiliation) {
            $schema['mainEntity']['affiliation'] = [
                '@type' => 'Organization',
                'name' => $affiliation
            ];
        }

        return $schema;
    }

    /**
     * Generate enhanced Product schema with 2025 properties
     *
     * @param \WC_Product $product WooCommerce product object.
     * @param array       $config Configuration options.
     * @return array Schema data.
     */
    public function generate_enhanced_product($product, $config = []): array {
        if (!function_exists('wc_get_product')) {
            return [];
        }

        $schema = [
            '@context' => 'https://schema.org',
            '@type' => 'Product',
            'name' => $product->get_name(),
            'url' => get_permalink($product->get_id()),
            'description' => $product->get_description() ?: $product->get_short_description(),
        ];

        // Add image
        $image_id = $product->get_image_id();
        if ($image_id) {
            $image = wp_get_attachment_image_src($image_id, 'full');
            if ($image) {
                $schema['image'] = [
                    '@type' => 'ImageObject',
                    'url' => $image[0],
                    'width' => $image[1],
                    'height' => $image[2]
                ];
            }
        }

        // Add SKU
        if ($product->get_sku()) {
            $schema['sku'] = $product->get_sku();
        }

        // Add brand
        $brand = get_post_meta($product->get_id(), '_product_brand', true);
        if ($brand) {
            $schema['brand'] = [
                '@type' => 'Brand',
                'name' => $brand
            ];
        }

        // Add GTIN
        $gtin = get_post_meta($product->get_id(), '_product_gtin', true);
        if ($gtin) {
            $schema['gtin'] = $gtin;
        }

        // Add MPN
        $mpn = get_post_meta($product->get_id(), '_product_mpn', true);
        if ($mpn) {
            $schema['mpn'] = $mpn;
        }

        // Add offers
        $schema['offers'] = [
            '@type' => 'Offer',
            'url' => get_permalink($product->get_id()),
            'priceCurrency' => get_woocommerce_currency(),
            'price' => $product->get_price(),
            'priceValidUntil' => gmdate('Y-m-d', strtotime('+1 year')),
            'availability' => $this->get_product_availability($product),
            'itemCondition' => 'https://schema.org/NewCondition',
        ];

        // 2025 ENHANCEMENT: Add shippingDetails
        $shipping_class = $product->get_shipping_class();
        if ($shipping_class) {
            $schema['offers']['shippingDetails'] = [
                '@type' => 'OfferShippingDetails',
                'shippingRate' => [
                    '@type' => 'MonetaryAmount',
                    'value' => $this->get_shipping_cost($product),
                    'currency' => get_woocommerce_currency()
                ],
                'deliveryTime' => [
                    '@type' => 'ShippingDeliveryTime',
                    'handlingTime' => [
                        '@type' => 'QuantitativeValue',
                        'minValue' => 1,
                        'maxValue' => 3,
                        'unitCode' => 'DAY'
                    ],
                    'transitTime' => [
                        '@type' => 'QuantitativeValue',
                        'minValue' => 2,
                        'maxValue' => 5,
                        'unitCode' => 'DAY'
                    ]
                ]
            ];
        }

        // 2025 ENHANCEMENT: Add hasMerchantReturnPolicy
        $return_policy = get_option('woocommerce_return_policy_text', '');
        if ($return_policy) {
            $schema['offers']['hasMerchantReturnPolicy'] = [
                '@type' => 'MerchantReturnPolicy',
                'returnPolicyCategory' => 'https://schema.org/MerchantReturnFiniteReturnWindow',
                'merchantReturnDays' => 30,
                'returnMethod' => 'https://schema.org/ReturnByMail',
                'returnFees' => 'https://schema.org/FreeReturn',
                'returnPolicyCountry' => WC()->countries->get_base_country()
            ];
        }

        // Add aggregate rating
        $average_rating = $product->get_average_rating();
        $review_count = $product->get_review_count();

        if ($average_rating && $review_count > 0) {
            $schema['aggregateRating'] = [
                '@type' => 'AggregateRating',
                'ratingValue' => $average_rating,
                'reviewCount' => $review_count,
                'bestRating' => 5,
                'worstRating' => 1
            ];
        }

        // 2025 ENHANCEMENT: Add sustainability information
        $sustainability = get_post_meta($product->get_id(), '_product_sustainability', true);
        if ($sustainability) {
            $schema['additionalProperty'] = [
                '@type' => 'PropertyValue',
                'name' => 'Sustainability',
                'value' => $sustainability
            ];
        }

        return $schema;
    }

    /**
     * Generate enhanced VideoObject schema with 2025 properties
     *
     * @param array $video_data Video data array.
     * @param array $config Configuration options.
     * @return array Schema data.
     */
    public function generate_enhanced_video($video_data, $config = []): array {
        $schema = [
            '@context' => 'https://schema.org',
            '@type' => 'VideoObject',
            'name' => $video_data['name'] ?? '',
            'description' => $video_data['description'] ?? '',
            'thumbnailUrl' => $video_data['thumbnail'] ?? '',
            'uploadDate' => $video_data['uploadDate'] ?? current_time('c'),
        ];

        // Add content URL
        if (!empty($video_data['url'])) {
            $schema['contentUrl'] = $video_data['url'];
        }

        // Add embed URL
        if (!empty($video_data['embedUrl'])) {
            $schema['embedUrl'] = $video_data['embedUrl'];
        }

        // Add duration
        if (!empty($video_data['duration'])) {
            $schema['duration'] = $video_data['duration'];
        }

        // 2025 ENHANCEMENT: Add video clips (hasPart)
        if (!empty($video_data['clips']) && is_array($video_data['clips'])) {
            $schema['hasPart'] = [];

            foreach ($video_data['clips'] as $clip) {
                $schema['hasPart'][] = [
                    '@type' => 'Clip',
                    'name' => $clip['name'] ?? '',
                    'startOffset' => $clip['startOffset'] ?? 0,
                    'endOffset' => $clip['endOffset'] ?? 0,
                    'url' => $clip['url'] ?? ''
                ];
            }
        }

        // 2025 ENHANCEMENT: Add regionsAllowed
        if (!empty($video_data['regionsAllowed'])) {
            $schema['regionsAllowed'] = $video_data['regionsAllowed'];
        }

        // 2025 ENHANCEMENT: Add interactionStatistic
        if (!empty($video_data['views'])) {
            $schema['interactionStatistic'] = [
                '@type' => 'InteractionCounter',
                'interactionType' => 'https://schema.org/WatchAction',
                'userInteractionCount' => (int) $video_data['views']
            ];
        }

        return $schema;
    }

    /**
     * Generate enhanced LocalBusiness schema with 2025 properties
     *
     * @param array $business_data Business data array.
     * @param array $config Configuration options.
     * @return array Schema data.
     */
    public function generate_enhanced_local_business($business_data, $config = []): array {
        $schema = [
            '@context' => 'https://schema.org',
            '@type' => $business_data['type'] ?? 'LocalBusiness',
            'name' => $business_data['name'] ?? get_bloginfo('name'),
            'url' => $business_data['url'] ?? home_url(),
        ];

        // Add address
        if (!empty($business_data['address'])) {
            $schema['address'] = [
                '@type' => 'PostalAddress',
                'streetAddress' => $business_data['address']['street'] ?? '',
                'addressLocality' => $business_data['address']['city'] ?? '',
                'addressRegion' => $business_data['address']['state'] ?? '',
                'postalCode' => $business_data['address']['zip'] ?? '',
                'addressCountry' => $business_data['address']['country'] ?? ''
            ];
        }

        // Add geo coordinates
        if (!empty($business_data['latitude']) && !empty($business_data['longitude'])) {
            $schema['geo'] = [
                '@type' => 'GeoCoordinates',
                'latitude' => $business_data['latitude'],
                'longitude' => $business_data['longitude']
            ];
        }

        // Add contact information
        if (!empty($business_data['telephone'])) {
            $schema['telephone'] = $business_data['telephone'];
        }

        if (!empty($business_data['email'])) {
            $schema['email'] = $business_data['email'];
        }

        // 2025 ENHANCEMENT: Add multiple areaServed
        if (!empty($business_data['areasServed']) && is_array($business_data['areasServed'])) {
            $schema['areaServed'] = [];

            foreach ($business_data['areasServed'] as $area) {
                $schema['areaServed'][] = [
                    '@type' => 'City',
                    'name' => $area
                ];
            }
        }

        // 2025 ENHANCEMENT: Enhanced opening hours with special days
        if (!empty($business_data['openingHours']) && is_array($business_data['openingHours'])) {
            $schema['openingHoursSpecification'] = [];

            foreach ($business_data['openingHours'] as $hours) {
                $opening_hours = [
                    '@type' => 'OpeningHoursSpecification',
                    'dayOfWeek' => $hours['dayOfWeek'] ?? [],
                    'opens' => $hours['opens'] ?? '09:00',
                    'closes' => $hours['closes'] ?? '17:00'
                ];

                // Add special opening hours (holidays, etc.)
                if (!empty($hours['validFrom'])) {
                    $opening_hours['validFrom'] = $hours['validFrom'];
                }

                if (!empty($hours['validThrough'])) {
                    $opening_hours['validThrough'] = $hours['validThrough'];
                }

                $schema['openingHoursSpecification'][] = $opening_hours;
            }
        }

        // Add aggregate rating
        if (!empty($business_data['rating']) && !empty($business_data['reviewCount'])) {
            $schema['aggregateRating'] = [
                '@type' => 'AggregateRating',
                'ratingValue' => $business_data['rating'],
                'reviewCount' => $business_data['reviewCount'],
                'bestRating' => 5,
                'worstRating' => 1
            ];
        }

        // Add price range
        if (!empty($business_data['priceRange'])) {
            $schema['priceRange'] = $business_data['priceRange'];
        }

        return $schema;
    }

    /**
     * Get author as Person schema
     *
     * @param \WP_Post $post The post object.
     * @return array Person schema.
     */
    private function get_author_person($post): array {
        $author = get_userdata($post->post_author);
        if (!$author) {
            return [];
        }

        $person = [
            '@type' => 'Person',
            'name' => $author->display_name
        ];

        if ($author->user_url) {
            $person['url'] = $author->user_url;
        }

        $avatar_url = get_avatar_url($author->ID);
        if ($avatar_url) {
            $person['image'] = $avatar_url;
        }

        return $person;
    }

    /**
     * Get share count for a post
     *
     * @param int $post_id The post ID.
     * @return int Share count.
     */
    private function get_share_count($post_id): int {
        $share_count = get_post_meta($post_id, '_share_count', true);
        return $share_count ? (int) $share_count : 0;
    }

    /**
     * Get product availability schema URL
     *
     * @param \WC_Product $product WooCommerce product.
     * @return string Schema.org availability URL.
     */
    private function get_product_availability($product): string {
        if (!$product->is_in_stock()) {
            return 'https://schema.org/OutOfStock';
        }

        if ($product->is_on_backorder()) {
            return 'https://schema.org/BackOrder';
        }

        if ($product->get_stock_quantity() && $product->get_stock_quantity() < 5) {
            return 'https://schema.org/LimitedAvailability';
        }

        return 'https://schema.org/InStock';
    }

    /**
     * Get shipping cost for a product
     *
     * @param \WC_Product $product WooCommerce product.
     * @return float Shipping cost.
     */
    private function get_shipping_cost($product): float {
        $shipping_class_id = $product->get_shipping_class_id();

        if (!$shipping_class_id) {
            return 0.0;
        }

        $cost = get_post_meta($product->get_id(), '_shipping_cost', true);

        return $cost ? (float) $cost : 0.0;
    }
}
