<?php
declare(strict_types=1);

namespace Help4BuilderSuite\Modules\SEO;

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

final class PerformingArtsSchema
{
    /** @return array<string, mixed> */
    public function forPost(int $postId): array
    {
        $value = get_post_meta($postId, '_h4_seo_performing_arts', true);
        return $this->sanitize(is_array($value) ? $value : []);
    }

    /** @param array<string, mixed> $raw @return array<string, mixed> */
    public function sanitize(array $raw): array
    {
        $eventStatus = sanitize_key((string) ($raw['event_status'] ?? 'scheduled'));
        if (! in_array($eventStatus, ['scheduled', 'cancelled', 'postponed', 'rescheduled', 'moved_online'], true)) $eventStatus = 'scheduled';
        $attendance = sanitize_key((string) ($raw['attendance_mode'] ?? 'offline'));
        if (! in_array($attendance, ['offline', 'online', 'mixed'], true)) $attendance = 'offline';
        return [
            'event_start' => $this->dateTime((string) ($raw['event_start'] ?? '')),
            'event_end' => $this->dateTime((string) ($raw['event_end'] ?? '')),
            'event_status' => $eventStatus,
            'attendance_mode' => $attendance,
            'venue_name' => sanitize_text_field((string) ($raw['venue_name'] ?? '')),
            'street_address' => sanitize_text_field((string) ($raw['street_address'] ?? '')),
            'address_locality' => sanitize_text_field((string) ($raw['address_locality'] ?? '')),
            'address_region' => sanitize_text_field((string) ($raw['address_region'] ?? '')),
            'postal_code' => sanitize_text_field((string) ($raw['postal_code'] ?? '')),
            'address_country' => strtoupper(substr(sanitize_text_field((string) ($raw['address_country'] ?? 'US')), 0, 2)),
            'organizer_name' => sanitize_text_field((string) ($raw['organizer_name'] ?? '')),
            'organizer_url' => esc_url_raw((string) ($raw['organizer_url'] ?? '')),
            'performer_names' => $this->lines($raw['performer_names'] ?? []),
            'offer_url' => esc_url_raw((string) ($raw['offer_url'] ?? '')),
            'offer_price' => ! isset($raw['offer_price']) || $raw['offer_price'] === '' ? '' : max(0, (float) $raw['offer_price']),
            'offer_currency' => strtoupper(substr(sanitize_text_field((string) ($raw['offer_currency'] ?? 'USD')), 0, 3)),
            'course_provider_name' => sanitize_text_field((string) ($raw['course_provider_name'] ?? '')),
            'course_provider_url' => esc_url_raw((string) ($raw['course_provider_url'] ?? '')),
            'course_outcome' => sanitize_textarea_field((string) ($raw['course_outcome'] ?? '')),
            'course_mode' => sanitize_text_field((string) ($raw['course_mode'] ?? '')),
            'course_prerequisites' => sanitize_textarea_field((string) ($raw['course_prerequisites'] ?? '')),
            'course_instructors' => $this->lines($raw['course_instructors'] ?? []),
        ];
    }

    /** @param array<string, mixed> $data @param array<string, mixed> $base @return array<string, mixed> */
    public function extend(array $base, string $schemaType, array $data): array
    {
        if ($schemaType === 'Event') {
            if ($data['event_start'] === '' || $data['venue_name'] === '' || $data['street_address'] === '' || $data['address_locality'] === '') return $base;
            $base['startDate'] = $data['event_start'];
            if ($data['event_end'] !== '') $base['endDate'] = $data['event_end'];
            $status = ['scheduled'=>'EventScheduled','cancelled'=>'EventCancelled','postponed'=>'EventPostponed','rescheduled'=>'EventRescheduled','moved_online'=>'EventMovedOnline'][$data['event_status']];
            $mode = ['offline'=>'OfflineEventAttendanceMode','online'=>'OnlineEventAttendanceMode','mixed'=>'MixedEventAttendanceMode'][$data['attendance_mode']];
            $base['eventStatus'] = 'https://schema.org/' . $status;
            $base['eventAttendanceMode'] = 'https://schema.org/' . $mode;
            $base['location'] = ['@type'=>'Place','name'=>$data['venue_name'],'address'=>['@type'=>'PostalAddress','streetAddress'=>$data['street_address'],'addressLocality'=>$data['address_locality'],'addressRegion'=>$data['address_region'],'postalCode'=>$data['postal_code'],'addressCountry'=>$data['address_country']]];
            if ($data['organizer_name'] !== '') $base['organizer'] = ['@type'=>'Organization','name'=>$data['organizer_name'],'url'=>$data['organizer_url']];
            if ($data['performer_names']) $base['performer'] = array_map(static fn(string $name): array => ['@type'=>'PerformingGroup','name'=>$name], $data['performer_names']);
            if ($data['offer_url'] !== '') $base['offers'] = ['@type'=>'Offer','url'=>$data['offer_url'],'price'=>$data['offer_price'],'priceCurrency'=>$data['offer_currency'],'availability'=>'https://schema.org/InStock'];
        }
        if ($schemaType === 'Course') {
            if ($data['course_provider_name'] === '' || $data['course_outcome'] === '') return $base;
            $base['provider'] = ['@type'=>'Organization','name'=>$data['course_provider_name'],'sameAs'=>$data['course_provider_url']];
            $base['teaches'] = $data['course_outcome'];
            if ($data['course_mode'] !== '') $base['courseMode'] = $data['course_mode'];
            if ($data['course_prerequisites'] !== '') $base['coursePrerequisites'] = $data['course_prerequisites'];
            if ($data['course_instructors']) $base['provider']['employee'] = array_map(static fn(string $name): array => ['@type'=>'Person','name'=>$name], $data['course_instructors']);
        }
        return $base;
    }

    /** @param array<string, mixed> $data */
    public function eligible(string $schemaType, array $data): bool
    {
        if ($schemaType === 'Event') return $data['event_start'] !== '' && $data['venue_name'] !== '' && $data['street_address'] !== '' && $data['address_locality'] !== '';
        if ($schemaType === 'Course') return $data['course_provider_name'] !== '' && $data['course_outcome'] !== '';
        return true;
    }

    /** @param array<int, array<string, mixed>> $records @return array<string, mixed> */
    public function courseItemList(array $records, string $baseUrl = ''): array
    {
        $items = [];
        $seen = [];
        foreach ($records as $record) {
            if (! is_array($record) || ! empty($record['hidden']) || in_array(($record['status'] ?? 'publish'), ['draft', 'hidden', 'archive'], true)) continue;
            $name = sanitize_text_field((string) ($record['name'] ?? $record['title'] ?? ''));
            $description = sanitize_textarea_field((string) ($record['description'] ?? ''));
            $url = esc_url_raw((string) ($record['url'] ?? ''));
            if (str_starts_with($url, '#') && $baseUrl !== '') $url = rtrim($baseUrl, '#') . $url;
            $provider = sanitize_text_field((string) ($record['provider_name'] ?? ''));
            $goals = $this->lines($record['learning_goals'] ?? $record['outcome'] ?? []);
            $credential = sanitize_text_field((string) ($record['credential'] ?? ''));
            if ($name === '' || $description === '' || $url === '' || $provider === '' || $goals === [] || isset($seen[$url])) continue;
            $seen[$url] = true;
            $course = ['@type'=>'Course','name'=>$name,'description'=>$description,'url'=>$url,'provider'=>['@type'=>'Organization','name'=>$provider],'teaches'=>$goals];
            if ($credential !== '') $course['educationalCredentialAwarded'] = $credential;
            foreach (['level'=>'educationalLevel','ages'=>'typicalAgeRange','discipline'=>'about','schedule'=>'courseMode'] as $source=>$target) if (trim((string) ($record[$source] ?? '')) !== '') $course[$target] = sanitize_text_field((string) $record[$source]);
            $items[] = ['@type'=>'ListItem','position'=>count($items) + 1,'url'=>$url,'item'=>$course];
        }
        if (count($items) < 3) return [];
        return ['@context'=>'https://schema.org','@type'=>'ItemList','numberOfItems'=>count($items),'itemListElement'=>$items];
    }

    private function dateTime(string $value): string
    {
        $value = sanitize_text_field($value);
        return preg_match('/^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}(?::\d{2})?(?:Z|[+-]\d{2}:\d{2})?)?$/', $value) ? $value : '';
    }

    /** @return array<int, string> */
    private function lines($value): array
    {
        $rows = is_array($value) ? $value : preg_split('/\r?\n/', (string) $value);
        return array_values(array_filter(array_map('sanitize_text_field', (array) $rows)));
    }
}
