<?php
namespace Crawl\Services;

/**
 * Validates JSON-LD structured data against required fields per schema type.
 */
class SchemaValidatorService
{
    private const REQUIRED = [
        'Article'       => ['headline', 'author', 'datePublished'],
        'NewsArticle'   => ['headline', 'author', 'datePublished'],
        'BlogPosting'   => ['headline', 'author', 'datePublished'],
        'Product'       => ['name', 'image', 'offers'],
        'FAQPage'       => ['mainEntity'],
        'HowTo'         => ['name', 'step'],
        'Recipe'        => ['name', 'recipeIngredient', 'recipeInstructions'],
        'Event'         => ['name', 'startDate', 'location'],
        'LocalBusiness' => ['name', 'address', 'telephone'],
        'Organization'  => ['name', 'url'],
        'Person'        => ['name'],
        'WebPage'       => ['name'],
        'BreadcrumbList'=> ['itemListElement'],
        'VideoObject'   => ['name', 'description', 'thumbnailUrl', 'uploadDate'],
        'Review'        => ['reviewRating', 'author'],
    ];

    /**
     * Validate a single page's json_ld_schema string.
     * Returns array of validation results.
     */
    public function validatePage(string $url, string $schemaJson): array
    {
        if (empty($schemaJson) || $schemaJson === 'null' || $schemaJson === '[]') {
            return [];
        }

        $schemas = json_decode($schemaJson, true);
        if (!is_array($schemas)) return [];

        // Handle both single object and array
        if (isset($schemas['@type'])) $schemas = [$schemas];

        $results = [];
        foreach ($schemas as $schema) {
            // HtmlParser stores each JSON-LD block as a raw JSON string inside the array.
            // Decode the string a second time to get the actual associative array.
            if (is_string($schema)) {
                $schema = json_decode($schema, true);
            }
            if (!is_array($schema)) continue;
            $type = $this->extractType($schema);
            if (!$type) continue;

            $required = self::REQUIRED[$type] ?? [];
            $missing  = [];
            foreach ($required as $field) {
                if (!isset($schema[$field]) || $schema[$field] === '' || $schema[$field] === null) {
                    $missing[] = $field;
                }
            }

            $results[] = [
                'url'       => $url,
                'type'      => $type,
                'valid'     => empty($missing),
                'missing'   => $missing,
                'known'     => isset(self::REQUIRED[$type]),
            ];
        }

        return $results;
    }

    /**
     * Validate all pages from a crawl run and return a summary + issues.
     */
    public function validateRun(array $pages): array
    {
        $results  = [];
        $typeCounts = [];
        $errorCount = 0;

        foreach ($pages as $page) {
            $schema = (string)($page['json_ld_schema'] ?? '');
            $rows   = $this->validatePage($page['url'], $schema);
            foreach ($rows as $row) {
                $results[] = $row;
                $typeCounts[$row['type']] = ($typeCounts[$row['type']] ?? 0) + 1;
                if (!$row['valid']) $errorCount++;
            }
        }

        arsort($typeCounts);

        return [
            'total_schemas' => count($results),
            'type_counts'   => $typeCounts,
            'error_count'   => $errorCount,
            'results'       => $results,
        ];
    }

    private function extractType(array $schema): ?string
    {
        $type = $schema['@type'] ?? null;
        if (is_array($type)) $type = $type[0] ?? null;
        return is_string($type) ? $type : null;
    }
}
