<?php
declare(strict_types=1);

namespace Help4BuilderSuite\Modules\StaffDirectory;

use Help4BuilderSuite\Support\RobotsContract;

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

final class Workspace
{
    public const OPTION = 'h4bs_staff_directory_workspace';
    public const SCHEMA = '1.0';
    public const TIERS = ['owner', 'leadership', 'faculty', 'guest', 'operations'];
    public const STATES = ['published', 'draft', 'hidden', 'archived'];

    /** @return array<string, mixed> */
    public static function load(): array
    {
        $saved = get_option(self::OPTION, []);
        return self::sanitize(is_array($saved) ? $saved : []);
    }

    /** @param array<string, mixed> $input @return array<string, mixed> */
    public static function sanitize(array $input): array
    {
        $profiles = [];
        foreach ((array) ($input['profiles'] ?? []) as $profile) {
            if (! is_array($profile)) continue;
            $clean = self::sanitizeProfile($profile);
            if ($clean['name'] !== '') $profiles[] = $clean;
        }
        usort($profiles, static fn(array $a, array $b): int => [$a['tier_order'], $a['sort_order'], $a['name']] <=> [$b['tier_order'], $b['sort_order'], $b['name']]);
        $ownerIndexes = [];
        foreach ($profiles as $index => $profile) if ($profile['tier'] === 'owner') $ownerIndexes[] = $index;
        if (count($ownerIndexes) > 1) {
            foreach (array_slice($ownerIndexes, 1) as $index) {
                $profiles[$index]['tier'] = 'leadership';
                $profiles[$index]['tier_order'] = 1;
                $profiles[$index]['owner_locked'] = false;
            }
        }
        if ($ownerIndexes) {
            $owner = $ownerIndexes[0];
            $profiles[$owner]['state'] = 'published';
            $profiles[$owner]['owner_locked'] = true;
            $profiles[$owner]['sort_order'] = 0;
        }
        return [
            'schema_version' => self::SCHEMA,
            'revision' => max(1, (int) ($input['revision'] ?? 1)),
            'updated_at' => sanitize_text_field((string) ($input['updated_at'] ?? '')),
            'profiles' => array_values($profiles),
            'presentation' => self::presentation((array) ($input['presentation'] ?? [])),
            'extensions' => self::opaque((array) ($input['extensions'] ?? [])),
        ];
    }

    /** @param array<string, mixed> $profile @return array<string, mixed> */
    private static function sanitizeProfile(array $profile): array
    {
        $tier = sanitize_key((string) ($profile['tier'] ?? 'faculty'));
        if (! in_array($tier, self::TIERS, true)) $tier = 'faculty';
        $state = sanitize_key((string) ($profile['state'] ?? 'draft'));
        if (! in_array($state, self::STATES, true)) $state = 'draft';
        $titles = array_values(array_filter(array_map('sanitize_text_field', (array) ($profile['title_lines'] ?? []))));
        $disciplines = array_values(array_filter(array_map('sanitize_text_field', (array) ($profile['disciplines'] ?? []))));
        $credentials = array_values(array_filter(array_map('sanitize_text_field', (array) ($profile['credentials'] ?? []))));
        $social = [];
        foreach ((array) ($profile['social_links'] ?? []) as $link) {
            if (! is_array($link)) continue;
            $url = esc_url_raw((string) ($link['url'] ?? ''));
            if ($url !== '') $social[] = ['label' => sanitize_text_field((string) ($link['label'] ?? 'Profile')), 'url' => $url];
        }
        $id = sanitize_key((string) ($profile['id'] ?? ''));
        if ($id === '') $id = 'staff-' . wp_generate_uuid4();
        $span = static function ($value, int $default): int { return max(1, min(12, (int) ($value ?: $default))); };
        return [
            'id' => $id,
            'name' => sanitize_text_field((string) ($profile['name'] ?? '')),
            'slug' => sanitize_title((string) ($profile['slug'] ?? ($profile['name'] ?? ''))),
            'tier' => $tier,
            'tier_order' => array_search($tier, self::TIERS, true),
            'sort_order' => max(0, (int) ($profile['sort_order'] ?? 0)),
            'state' => $state,
            'owner_locked' => $tier === 'owner' && ! empty($profile['owner_locked']),
            'featured' => ! empty($profile['featured']),
            'portrait_id' => absint($profile['portrait_id'] ?? 0),
            'portrait_url' => esc_url_raw((string) ($profile['portrait_url'] ?? '')),
            'portrait_alt' => sanitize_text_field((string) ($profile['portrait_alt'] ?? '')),
            'focal_desktop' => self::focal((string) ($profile['focal_desktop'] ?? '50% 35%')),
            'focal_tablet' => self::focal((string) ($profile['focal_tablet'] ?? '50% 35%')),
            'focal_mobile' => self::focal((string) ($profile['focal_mobile'] ?? '50% 30%')),
            'crop_mode' => in_array(($profile['crop_mode'] ?? ''), ['cover', 'contain', 'natural'], true) ? $profile['crop_mode'] : 'cover',
            'span_desktop' => $span($profile['span_desktop'] ?? 0, $tier === 'owner' ? 12 : 4),
            'span_tablet' => $span($profile['span_tablet'] ?? 0, $tier === 'owner' ? 12 : 6),
            'span_mobile' => 12,
            'title_lines' => $titles,
            'disciplines' => $disciplines,
            'credentials' => $credentials,
            'short_bio' => sanitize_textarea_field((string) ($profile['short_bio'] ?? '')),
            'full_bio' => wp_kses_post((string) ($profile['full_bio'] ?? '')),
            'email' => sanitize_email((string) ($profile['email'] ?? '')),
            'phone' => sanitize_text_field((string) ($profile['phone'] ?? '')),
            'cta_label' => sanitize_text_field((string) ($profile['cta_label'] ?? 'View profile')),
            'cta_url' => esc_url_raw((string) ($profile['cta_url'] ?? '')),
            'social_links' => $social,
            'seo_title' => sanitize_text_field((string) ($profile['seo_title'] ?? '')),
            'seo_description' => sanitize_textarea_field((string) ($profile['seo_description'] ?? '')),
            'schema_job_title' => sanitize_text_field((string) ($profile['schema_job_title'] ?? '')),
            'schema_works_for' => sanitize_text_field((string) ($profile['schema_works_for'] ?? '')),
            'schema_same_as' => array_values(array_filter(array_map('esc_url_raw', (array) ($profile['schema_same_as'] ?? [])))),
            'internal_links' => array_values(array_filter(array_map('esc_url_raw', (array) ($profile['internal_links'] ?? [])))),
            'extensions' => self::opaque((array) ($profile['extensions'] ?? [])),
        ];
    }

    /** @param array<string, mixed> $input @return array<string, mixed> */
    private static function presentation(array $input): array
    {
        return [
            'columns' => max(1, min(6, (int) ($input['columns'] ?? 3))),
            'columns_tablet' => max(1, min(4, (int) ($input['columns_tablet'] ?? 2))),
            'columns_mobile' => 1,
            'show_tier_headings' => ! array_key_exists('show_tier_headings', $input) || ! empty($input['show_tier_headings']),
            'show_search' => ! array_key_exists('show_search', $input) || ! empty($input['show_search']),
            'empty_text' => sanitize_text_field((string) ($input['empty_text'] ?? __('No staff profiles match this view.', 'help4-builder-suite'))),
        ];
    }

    private static function focal(string $value): string
    {
        return preg_match('/^(?:100|[0-9]{1,2})%\s+(?:100|[0-9]{1,2})%$/', trim($value)) ? trim($value) : '50% 35%';
    }

    /** @param array<mixed> $value @return array<mixed> */
    private static function opaque(array $value): array
    {
        $clean = [];
        foreach ($value as $key => $item) {
            $safe = is_int($key) ? $key : sanitize_key((string) $key);
            if ($safe === '' && ! is_int($safe)) continue;
            $clean[$safe] = is_array($item) ? self::opaque($item) : (is_scalar($item) || $item === null ? $item : null);
        }
        return $clean;
    }

    /** @param array<string, mixed> $settings */
    public static function render(array $settings = []): string
    {
        $data = self::load();
        $profiles = array_values(array_filter($data['profiles'], static fn(array $profile): bool => $profile['state'] === 'published'));
        $presentation = array_merge($data['presentation'], array_intersect_key($settings, $data['presentation']));
        $labels = ['owner' => __('Owner / Founder', 'help4-builder-suite'), 'leadership' => __('Directors & Leadership', 'help4-builder-suite'), 'faculty' => __('Faculty / Teaching Artists', 'help4-builder-suite'), 'guest' => __('Guest Faculty', 'help4-builder-suite'), 'operations' => __('Production / Operations', 'help4-builder-suite')];
        ob_start();
        ?><section class="h4bs-staff-directory" data-h4bs-staff-directory style="--h4bs-staff-columns:<?php echo (int) $presentation['columns']; ?>;--h4bs-staff-columns-tablet:<?php echo (int) $presentation['columns_tablet']; ?>;--h4bs-staff-columns-mobile:1">
        <?php if ($presentation['show_search']) : ?><label class="h4bs-staff-search"><span><?php esc_html_e('Search staff', 'help4-builder-suite'); ?></span><input type="search" data-h4bs-staff-search></label><?php endif; ?>
        <div data-h4bs-staff-groups><?php foreach (self::TIERS as $tier) : $tierProfiles = array_values(array_filter($profiles, static fn(array $profile): bool => $profile['tier'] === $tier)); if (! $tierProfiles) continue; ?>
            <section class="h4bs-staff-tier" data-tier="<?php echo esc_attr($tier); ?>"><?php if ($presentation['show_tier_headings']) : ?><h2><?php echo esc_html($labels[$tier]); ?></h2><?php endif; ?><div class="h4bs-staff-grid">
            <?php foreach ($tierProfiles as $profile) : $search = strtolower($profile['name'] . ' ' . implode(' ', $profile['title_lines']) . ' ' . implode(' ', $profile['disciplines'])); ?><article class="h4bs-staff-card<?php echo $profile['featured'] ? ' is-featured' : ''; ?>" data-h4bs-staff-card data-search="<?php echo esc_attr($search); ?>" style="--staff-span-desktop:<?php echo (int) $profile['span_desktop']; ?>;--staff-span-tablet:<?php echo (int) $profile['span_tablet']; ?>">
            <?php if ($profile['portrait_url'] !== '') : ?><img src="<?php echo esc_url($profile['portrait_url']); ?>" alt="<?php echo esc_attr($profile['portrait_alt']); ?>" loading="lazy" style="object-fit:<?php echo esc_attr($profile['crop_mode'] === 'natural' ? 'contain' : $profile['crop_mode']); ?>;--staff-focal-desktop:<?php echo esc_attr($profile['focal_desktop']); ?>;--staff-focal-tablet:<?php echo esc_attr($profile['focal_tablet']); ?>;--staff-focal-mobile:<?php echo esc_attr($profile['focal_mobile']); ?>"><?php endif; ?>
            <div class="h4bs-staff-card-content"><h3><?php echo esc_html($profile['name']); ?></h3><?php foreach ($profile['title_lines'] as $title) : ?><p class="h4bs-staff-title"><?php echo esc_html($title); ?></p><?php endforeach; ?><?php if ($profile['short_bio'] !== '') : ?><p><?php echo esc_html($profile['short_bio']); ?></p><?php endif; ?><?php if ($profile['cta_url'] !== '') : ?><a href="<?php echo esc_url($profile['cta_url']); ?>"><?php echo esc_html($profile['cta_label']); ?></a><?php endif; ?></div></article><?php endforeach; ?>
            </div></section><?php endforeach; ?></div><p data-h4bs-staff-empty hidden><?php echo esc_html($presentation['empty_text']); ?></p><p class="screen-reader-text" aria-live="polite" data-h4bs-staff-status></p></section><?php
        $html = (string) ob_get_clean();
        $graph = [];
        foreach ($profiles as $profile) {
            $person = ['@type'=>'Person','@id'=>($profile['cta_url'] !== '' ? $profile['cta_url'] : home_url('/')) . '#person-' . $profile['id'],'name'=>$profile['name']];
            if ($profile['schema_job_title'] !== '') $person['jobTitle'] = $profile['schema_job_title'];
            elseif ($profile['title_lines']) $person['jobTitle'] = implode(' / ', $profile['title_lines']);
            if ($profile['schema_works_for'] !== '') $person['worksFor'] = ['@type'=>'Organization','name'=>$profile['schema_works_for']];
            if ($profile['short_bio'] !== '') $person['description'] = $profile['short_bio'];
            if ($profile['portrait_url'] !== '') $person['image'] = $profile['portrait_url'];
            if ($profile['cta_url'] !== '') $person['url'] = $profile['cta_url'];
            if ($profile['disciplines']) $person['knowsAbout'] = $profile['disciplines'];
            if ($profile['credentials']) $person['hasCredential'] = array_map(static fn(string $credential): array => ['@type'=>'EducationalOccupationalCredential','name'=>$credential], $profile['credentials']);
            $sameAs = array_values(array_unique(array_merge($profile['schema_same_as'], array_column($profile['social_links'], 'url'))));
            if ($sameAs) $person['sameAs'] = $sameAs;
            $graph[] = apply_filters('h4bs_staff_person_schema', $person, $profile);
        }
        if ($graph && RobotsContract::isIndexable()) $html .= '<script type="application/ld+json" class="h4bs-staff-person-schema">' . wp_json_encode(['@context'=>'https://schema.org','@graph'=>$graph], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) . '</script>';
        return $html;
    }
}
