<?php
declare(strict_types=1);

namespace KbMarkdownImporter\Repository;

final class ProductRepository
{
    public function ensure(string $name, string $slug = ''): int
    {
        $slug = $slug ? sanitize_title($slug) : sanitize_title($name);
        $term = term_exists($slug, 'kb_product');

        if (! $term) {
            $term = wp_insert_term($name, 'kb_product', ['slug' => $slug]);
        }

        return is_wp_error($term) ? 0 : (int) ($term['term_id'] ?? $term);
    }

    public function allWithStats(): array
    {
        $terms = get_terms([
            'taxonomy' => 'kb_product',
            'hide_empty' => false,
            'orderby' => 'name',
            'order' => 'ASC',
        ]);

        if (is_wp_error($terms)) {
            return [];
        }

        $items = [];

        foreach ($terms as $term) {
            $pageIds = $this->pageIdsForProduct((int) $term->term_id);
            $versions = [];

            foreach ($pageIds as $pageId) {
                $pageVersions = wp_get_object_terms($pageId, 'kb_version');

                if (is_wp_error($pageVersions)) {
                    continue;
                }

                foreach ($pageVersions as $version) {
                    $versions[$version->slug] = $version;
                }
            }

            uasort($versions, static fn ($a, $b): int => strnatcasecmp($b->name, $a->name));

            $items[] = [
                'term' => $term,
                'page_count' => count($pageIds),
                'versions' => array_values($versions),
            ];
        }

        return $items;
    }

    public function update(int $termId, string $name, string $slug): \WP_Term|\WP_Error
    {
        $name = trim($name);
        $slug = sanitize_title($slug ?: $name);

        if ('' === $name || '' === $slug) {
            return new \WP_Error('kb_product_invalid', __('Product name and slug are required.', 'kb-markdown-importer'));
        }

        $updated = wp_update_term($termId, 'kb_product', [
            'name' => $name,
            'slug' => $slug,
        ]);

        if (is_wp_error($updated)) {
            return $updated;
        }

        foreach ($this->pageIdsForProduct($termId) as $pageId) {
            update_post_meta($pageId, '_kb_product_slug', $slug);
        }

        $term = get_term((int) $updated['term_id'], 'kb_product');

        return $term instanceof \WP_Term ? $term : new \WP_Error('kb_product_missing', __('Product could not be loaded after update.', 'kb-markdown-importer'));
    }

    public function trashProductPages(int $termId): int
    {
        $count = 0;

        foreach ($this->pageIdsForProduct($termId, ['publish', 'draft', 'private', 'pending', 'future']) as $pageId) {
            if (wp_trash_post($pageId)) {
                ++$count;
            }
        }

        return $count;
    }

    public function deleteProduct(int $termId, bool $trashPages): true|\WP_Error
    {
        if ($trashPages) {
            $this->trashProductPages($termId);
        }

        $deleted = wp_delete_term($termId, 'kb_product');

        if (is_wp_error($deleted)) {
            return $deleted;
        }

        return true;
    }

    private function pageIdsForProduct(int $termId, array $postStatus = ['publish']): array
    {
        $query = new \WP_Query([
            'post_type' => 'kb_doc_page',
            'post_status' => $postStatus,
            'posts_per_page' => -1,
            'fields' => 'ids',
            'tax_query' => [
                ['taxonomy' => 'kb_product', 'field' => 'term_id', 'terms' => $termId],
            ],
        ]);

        return array_map('intval', $query->posts);
    }
}
