<?php

declare(strict_types=1);

/**
 * Dataset Schema Service
 *
 * Single source of truth for building and rendering Dataset JSON-LD.
 * Required fields are `name` and `description`. Optional fields are emitted
 * only when present so a near-empty dataset entry never carries an empty
 * Person/Organization or license value.
 *
 * @package ProRank\SEO\Core\Services
 * @since 1.3.1
 */

namespace ProRank\SEO\Core\Services;

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


class DatasetSchemaService {

    private static bool $emitted = false;

    /**
     * @param array $config Config with keys:
     *     - name              (string, required)
     *     - description       (string, required)
     *     - url               (string, optional)
     *     - creator           (array{name,url?}|string, optional)
     *     - publisher         (array{name,url?}|string, optional)
     *     - license           (string, optional — URL of the license)
     *     - keywords          (string|array<string>, optional)
     *     - temporalCoverage  (string, optional)
     *     - spatialCoverage   (string, optional)
     *     - identifier        (string, optional)
     * @return array|null
     */
    public static function build_schema( array $config ): ?array {
        $name = trim( (string) ( $config['name'] ?? '' ) );
        $description = trim( (string) ( $config['description'] ?? '' ) );
        if ( $name === '' || $description === '' ) {
            return null;
        }

        $schema = [
            '@context'    => 'https://schema.org',
            '@type'       => 'Dataset',
            'name'        => wp_strip_all_tags( $name ),
            'description' => wp_strip_all_tags( $description ),
        ];

        $url = trim( (string) ( $config['url'] ?? '' ) );
        if ( $url !== '' ) {
            $clean = esc_url_raw( $url );
            if ( $clean !== '' ) {
                $schema['url'] = $clean;
            }
        }

        $creator = self::normalize_party( $config['creator'] ?? null );
        if ( $creator !== null ) {
            $schema['creator'] = $creator;
        }

        $publisher = self::normalize_party( $config['publisher'] ?? null );
        if ( $publisher !== null ) {
            $schema['publisher'] = $publisher;
        }

        $license = trim( (string) ( $config['license'] ?? '' ) );
        if ( $license !== '' ) {
            $clean = esc_url_raw( $license );
            if ( $clean !== '' ) {
                $schema['license'] = $clean;
            }
        }

        $keywords = self::normalize_keyword_list( $config['keywords'] ?? '' );
        if ( $keywords !== '' ) {
            $schema['keywords'] = $keywords;
        }

        $temporal = trim( (string) ( $config['temporalCoverage'] ?? '' ) );
        if ( $temporal !== '' ) {
            $schema['temporalCoverage'] = wp_strip_all_tags( $temporal );
        }

        $spatial = trim( (string) ( $config['spatialCoverage'] ?? '' ) );
        if ( $spatial !== '' ) {
            $schema['spatialCoverage'] = wp_strip_all_tags( $spatial );
        }

        $identifier = trim( (string) ( $config['identifier'] ?? '' ) );
        if ( $identifier !== '' ) {
            $schema['identifier'] = wp_strip_all_tags( $identifier );
        }

        return $schema;
    }

    public static function render_script( array $config, string $class_attr = '' ): string {
        $schema = self::build_schema( $config );

        if ( $schema === null ) {
            return '';
        }

        $class = $class_attr !== ''
            ? ' class="' . esc_attr( $class_attr ) . '"'
            : '';

        return '<script type="application/ld+json"' . $class . '>'
            . wp_json_encode( $schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE )
            . '</script>';
    }

    public static function mark_emitted(): void {
        self::$emitted = true;
    }

    public static function was_emitted(): bool {
        return self::$emitted;
    }

    public static function reset_for_tests(): void {
        self::$emitted = false;
    }

    /**
     * Normalize a creator/publisher into either an Organization (default) or
     * Person with a non-empty name. Returns null on no name.
     */
    private static function normalize_party( $value ): ?array {
        if ( is_string( $value ) ) {
            $value = [ 'name' => $value ];
        }
        if ( ! is_array( $value ) ) {
            return null;
        }
        $name = trim( wp_strip_all_tags( (string) ( $value['name'] ?? '' ) ) );
        if ( $name === '' ) {
            return null;
        }
        $type_input = strtolower( trim( (string) ( $value['type'] ?? '' ) ) );
        $type = $type_input === 'person' ? 'Person' : 'Organization';
        $out = [
            '@type' => $type,
            'name'  => $name,
        ];
        $url = trim( (string) ( $value['url'] ?? '' ) );
        if ( $url !== '' ) {
            $clean = esc_url_raw( $url );
            if ( $clean !== '' ) {
                $out['url'] = $clean;
            }
        }
        return $out;
    }

    private static function normalize_keyword_list( $value ): string {
        if ( is_array( $value ) ) {
            $items = $value;
        } else {
            $items = preg_split( '/[,\r\n]+/', (string) $value ) ?: [];
        }
        $clean = [];
        foreach ( $items as $item ) {
            $t = trim( wp_strip_all_tags( (string) $item ) );
            if ( $t !== '' ) {
                $clean[] = $t;
            }
        }
        return implode( ', ', $clean );
    }
}
