<?php
/**
 * Estimates how many pages a Bricks template condition would affect.
 *
 * @package LolaCoreForBricks
 */

declare(strict_types=1);

namespace LolaCoreForBricks\Support;

/**
 * Scope preview before saving templateConditions. Entire-site is the loudest case.
 */
final class TemplateConditionPreview
{
    public const EXAMPLE_LIMIT = 5;

    /**
     * @param array<int, mixed> $conditions
     * @return array<string, mixed>
     */
    public function preview(array $conditions): array
    {
        if ($conditions === []) {
            return [
                'pages'      => 0,
                'page_names' => [],
                'page_ids'   => [],
                'scope'      => 'default',
                'summary'    => 'No display conditions. Bricks will treat this as a default template.',
            ];
        }

        $ids    = [];
        $scopes = [];
        $notes  = [];

        foreach ($conditions as $condition) {
            if (!is_array($condition)) {
                continue;
            }

            $chunk = $this->previewOne($condition);
            $scopes[] = (string) ($chunk['scope'] ?? '');
            foreach ($chunk['page_ids'] as $pageId) {
                $ids[$pageId] = true;
            }
            if (($chunk['note'] ?? '') !== '') {
                $notes[] = (string) $chunk['note'];
            }
        }

        $pageIds = array_map('intval', array_keys($ids));
        $names   = [];
        foreach (array_slice($pageIds, 0, self::EXAMPLE_LIMIT) as $pageId) {
            $names[] = (string) get_the_title($pageId);
        }

        $scope   = $this->dominantScope($scopes);
        $summary = $this->summarize($scope, count($pageIds), $names, $notes);

        return [
            'pages'      => count($pageIds),
            'page_names' => $names,
            'page_ids'   => $pageIds,
            'scope'      => $scope,
            'summary'    => $summary,
        ];
    }

    /**
     * @param array<string, mixed> $condition
     * @return array{scope: string, page_ids: int[], note: string}
     */
    private function previewOne(array $condition): array
    {
        $main    = (string) ($condition['main'] ?? '');
        $exclude = !empty($condition['exclude']);

        return match ($main) {
            'any' => [
                'scope'    => $exclude ? 'exclude_entire_site' : 'entire_site',
                'page_ids' => $exclude ? [] : $this->publicContentIds(),
                'note'     => $exclude ? 'This condition excludes the entire website.' : '',
            ],
            'frontpage' => [
                'scope'    => 'front',
                'page_ids' => $this->frontPageIds(),
                'note'     => '',
            ],
            'postType' => [
                'scope'    => 'post_type',
                'page_ids' => $this->idsForPostTypes((array) ($condition['postType'] ?? [])),
                'note'     => '',
            ],
            'ids' => [
                'scope'    => 'ids',
                'page_ids' => $this->individualIds($condition),
                'note'     => '',
            ],
            'terms' => [
                'scope'    => 'terms',
                'page_ids' => [],
                'note'     => 'This applies to posts in the selected terms.',
            ],
            'archiveType' => [
                'scope'    => 'archive',
                'page_ids' => [],
                'note'     => 'This applies to archive views, not individual pages.',
            ],
            'search' => [
                'scope'    => 'search',
                'page_ids' => [],
                'note'     => 'This applies to search results.',
            ],
            'error' => [
                'scope'    => 'error',
                'page_ids' => [],
                'note'     => 'This applies to the error page.',
            ],
            default => [
                'scope'    => $main !== '' ? $main : 'unknown',
                'page_ids' => [],
                'note'     => '',
            ],
        };
    }

    /**
     * @return int[]
     */
    private function publicContentIds(): array
    {
        return $this->idsForPostTypes(['page', 'post']);
    }

    /**
     * @return int[]
     */
    private function frontPageIds(): array
    {
        $front = absint(get_option('page_on_front', 0));

        return $front > 0 ? [$front] : [];
    }

    /**
     * @param array<int|string, mixed> $types
     * @return int[]
     */
    private function idsForPostTypes(array $types): array
    {
        $wanted = [];
        foreach ($types as $type) {
            $type = sanitize_key((string) $type);
            if ($type !== '' && $type !== BricksMetaKeys::TEMPLATE_POST_TYPE) {
                $wanted[] = $type;
            }
        }

        if ($wanted === []) {
            return [];
        }

        if (function_exists('get_posts')) {
            $posts = get_posts([
                'post_type'      => $wanted,
                'post_status'    => 'publish',
                'posts_per_page' => 200,
                'orderby'        => 'title',
                'order'          => 'ASC',
            ]);

            $ids = [];
            foreach ($posts as $post) {
                $ids[] = is_object($post) ? (int) ($post->ID ?? 0) : (int) $post;
            }

            return array_values(array_filter($ids));
        }

        $ids = [];
        foreach ($GLOBALS['_test_posts'] ?? [] as $id => $data) {
            $type = is_array($data) ? (string) ($data['post_type'] ?? 'post') : 'post';
            if (in_array($type, $wanted, true)) {
                $ids[] = (int) $id;
            }
        }

        return $ids;
    }

    /**
     * @param array<string, mixed> $condition
     * @return int[]
     */
    private function individualIds(array $condition): array
    {
        $ids = [];
        foreach ((array) ($condition['ids'] ?? []) as $id) {
            $id = absint($id);
            if ($id > 0) {
                $ids[] = $id;
            }
        }

        return $ids;
    }

    /**
     * @param string[] $scopes
     */
    private function dominantScope(array $scopes): string
    {
        $scopes = array_values(array_filter($scopes));
        if (in_array('entire_site', $scopes, true)) {
            return 'entire_site';
        }

        $unique = array_values(array_unique($scopes));

        return $unique[0] ?? 'mixed';
    }

    /**
     * @param string[] $names
     * @param string[] $notes
     */
    private function summarize(string $scope, int $pages, array $names, array $notes): string
    {
        $examples = $names === [] ? '' : ' Examples: ' . implode(', ', $names) . '.';
        $extra    = $notes === [] ? '' : ' ' . implode(' ', $notes);

        $core = match ($scope) {
            'entire_site' => sprintf(
                'This would apply to the entire site — %d %s.',
                $pages,
                $pages === 1 ? 'page' : 'pages'
            ),
            'front' => 'This would apply to the front page.',
            'post_type' => sprintf(
                'This would apply to %d %s of the selected post type.',
                $pages,
                $pages === 1 ? 'page' : 'pages'
            ),
            'ids' => sprintf(
                'This would apply to %d selected %s.',
                $pages,
                $pages === 1 ? 'page' : 'pages'
            ),
            'terms' => 'This would apply to posts in the selected terms.',
            'archive' => 'This would apply to archive views, not individual pages.',
            'search' => 'This would apply to search results.',
            'error' => 'This would apply to the error page.',
            default => 'Condition preview is ready.',
        };

        return trim($core . $examples . $extra);
    }
}
