<?php
if (!defined('ABSPATH')) {
    exit;
}

/**
 * Service for managing taxonomies, term assignments, and generating filter options.
 */
class NEXDIRECTORY_Taxonomy_Service {

    /** @var string */
    private $tax_type;

    /** @var string */
    private $tax_mode;

    /** @var string */
    private $tax_tag;

    /** @var string */
    private $tax_price;

    /**
     * Constructor.
     */
    public function __construct(
        $tax_type = 'event_type',
        $tax_mode = 'event_mode',
        $tax_tag = 'event_tag',
        $tax_price = 'event_price_range'
    ) {
        $this->tax_type = sanitize_key($tax_type);
        $this->tax_mode = sanitize_key($tax_mode);
        $this->tax_tag = sanitize_key($tax_tag);
        $this->tax_price = sanitize_key($tax_price);
    }

    /**
     * Parses the stored JSON containing user-defined custom taxonomies.
     */
    public function get_custom_taxonomy_definitions() {
        $raw = (string) get_option('nexdirectory_custom_taxonomies', '[]');
        $decoded = json_decode($raw, true);
        if (!is_array($decoded)) {
            return [];
        }

        $reserved = [
            $this->tax_type,
            $this->tax_mode,
            $this->tax_tag,
            $this->tax_price,
            'category',
            'post_tag',
        ];
        
        $definitions = [];
        foreach ($decoded as $row) {
            if (!is_array($row)) {
                continue;
            }
            $slug_raw = (string) ($row['slug'] ?? '');
            $slug = nexdirectory_sanitize_title($slug_raw);
            
            if ($slug === '' || in_array($slug, $reserved, true)) {
                continue;
            }
            if (strpos($slug, 'nexdirectory_') !== 0) {
                $slug = 'nexdirectory_' . $slug;
            }
            
            $label = sanitize_text_field((string) ($row['label'] ?? ''));
            if ($label === '') {
                $label = ucwords(str_replace(['_', '-'], ' ', preg_replace('/^nexdirectory_/', '', $slug)));
            }
            
            $definitions[$slug] = [
                'slug'             => $slug,
                'label'            => $label,
                'hierarchical'     => (string) ($row['hierarchical'] ?? '1') === '0' ? '0' : '1',
                'show_on_submit'   => (string) ($row['show_on_submit'] ?? '1') === '0' ? '0' : '1',
                'show_on_overview' => (string) ($row['show_on_overview'] ?? '1') === '0' ? '0' : '1',
            ];
        }

        return array_values($definitions);
    }

    /**
     * Retrieves custom taxonomies that should be shown on the submission form.
     */
    public function get_custom_taxonomy_definitions_for_submit() {
        return array_values(array_filter($this->get_custom_taxonomy_definitions(), static function ($row) {
            return (string) ($row['show_on_submit'] ?? '1') === '1';
        }));
    }

    /**
     * Retrieves custom taxonomies that should be shown on the single post overview page.
     */
    public function get_custom_taxonomy_definitions_for_overview() {
        return array_values(array_filter($this->get_custom_taxonomy_definitions(), static function ($row) {
            return (string) ($row['show_on_overview'] ?? '1') === '1';
        }));
    }

    /**
     * Helper to split line or comma delimited text into arrays (used for tags and categories).
     */
    public function parse_delimited_values($raw) {
        if (is_array($raw)) {
            $items = $raw;
        } else {
            $items = preg_split('/[\\r\\n|,]+/', (string) $raw);
        }
        
        $items = array_map(static function ($v) {
            return sanitize_text_field((string) $v);
        }, (array) $items);
        
        return array_values(array_filter(array_map('trim', $items), static function ($v) {
            return $v !== '';
        }));
    }

    /**
     * Takes raw text/arrays, checks if terms exist (creates them if not), and assigns them to a post.
     */
    public function set_terms_from_values($post_id, $taxonomy, $raw_values) {
        $post_id = absint((int) $post_id);
        $taxonomy = sanitize_key((string) $taxonomy);
        
        if ($post_id <= 0 || $taxonomy === '') {
            return;
        }

        $values = $this->parse_delimited_values($raw_values);
        if (empty($values)) {
            return;
        }
        
        $term_ids = [];
        foreach ($values as $value) {
            $term = null;
            if (is_numeric($value)) {
                $term = get_term((int) $value, $taxonomy);
            }
            if (!$term || is_wp_error($term)) {
                $term = get_term_by('slug', nexdirectory_sanitize_title($value), $taxonomy);
            }
            if (!$term || is_wp_error($term)) {
                $term = get_term_by('name', $value, $taxonomy);
            }
            
            if (!$term || is_wp_error($term)) {
                $created = wp_insert_term($value, $taxonomy);
                if (!is_wp_error($created) && !empty($created['term_id'])) {
                    $term_ids[] = (int) $created['term_id'];
                }
            } else {
                $term_ids[] = (int) $term->term_id;
            }
        }
        
        if (!empty($term_ids)) {
            wp_set_post_terms($post_id, array_values(array_unique($term_ids)), $taxonomy, false);
        }
    }

    /**
     * Builds filter options specifically for a subset of post IDs.
     */
    public function build_archive_filter_options(array $post_ids, array $selected = [], $is_job_profile = false) {
        $post_ids = array_values(array_unique(array_filter(array_map('absint', $post_ids))));
        
        $taxonomy_map = [
            'event_type' => $this->tax_type,
            'event_mode' => $this->tax_mode,
            'event_tag'  => $this->tax_tag,
        ];
        
        if (!$is_job_profile) {
            $taxonomy_map['event_price'] = $this->tax_price;
        }
        
        $options = [];

        foreach ($taxonomy_map as $key => $taxonomy) {
            $rows = [];
            if (!empty($post_ids)) {
                $rows = wp_get_object_terms($post_ids, $taxonomy, [
                    'fields'     => 'all_with_object_id',
                    'orderby'    => 'name',
                    'order'      => 'ASC',
                    'hide_empty' => false,
                ]);
                if (is_wp_error($rows) || !is_array($rows)) {
                    $rows = [];
                }
            }

            $collected = [];
            foreach ($rows as $term) {
                if (!$term instanceof WP_Term) {
                    continue;
                }
                $slug = sanitize_key((string) $term->slug);
                if ($slug === '') {
                    continue;
                }
                if (!isset($collected[$slug])) {
                    $collected[$slug] = [
                        'slug'  => $slug,
                        'name'  => (string) $term->name,
                        'count' => 0,
                    ];
                }
                $collected[$slug]['count']++;
            }

            // Ensure currently selected item is in the list even if no results match
            $selected_slug = sanitize_key((string) ($selected[$key] ?? ''));
            if ($selected_slug !== '' && !isset($collected[$selected_slug])) {
                $selected_term = get_term_by('slug', $selected_slug, $taxonomy);
                if ($selected_term instanceof WP_Term) {
                    $collected[$selected_slug] = [
                        'slug'  => $selected_slug,
                        'name'  => (string) $selected_term->name,
                        'count' => 0,
                    ];
                }
            }

            $option_rows = array_values($collected);
            usort($option_rows, static function ($a, $b) {
                return strcasecmp((string) ($a['name'] ?? ''), (string) ($b['name'] ?? ''));
            });
            $options[$key] = $option_rows;
        }

        return $options;
    }

    /**
     * Builds globally available filter options (all terms with counts).
     */
    public function build_global_archive_filter_options(array $selected = [], $is_job_profile = false) {
        $taxonomy_map = [
            'event_type' => $this->tax_type,
            'event_mode' => $this->tax_mode,
            'event_tag'  => $this->tax_tag,
        ];
        
        if (!$is_job_profile) {
            $taxonomy_map['event_price'] = $this->tax_price;
        }
        
        $options = [];

        foreach ($taxonomy_map as $key => $taxonomy) {
            $rows = get_terms([
                'taxonomy'   => $taxonomy,
                'hide_empty' => true,
                'orderby'    => 'name',
                'order'      => 'ASC',
            ]);
            
            if (is_wp_error($rows) || !is_array($rows)) {
                $rows = [];
            }

            $collected = [];
            foreach ($rows as $term) {
                if (!$term instanceof WP_Term) {
                    continue;
                }
                $slug = sanitize_key((string) $term->slug);
                if ($slug === '') {
                    continue;
                }
                $collected[$slug] = [
                    'slug'  => $slug,
                    'name'  => (string) $term->name,
                    'count' => max(0, (int) $term->count),
                ];
            }

            // Ensure currently selected item is in the list
            $selected_slug = sanitize_key((string) ($selected[$key] ?? ''));
            if ($selected_slug !== '' && !isset($collected[$selected_slug])) {
                $selected_term = get_term_by('slug', $selected_slug, $taxonomy);
                if ($selected_term instanceof WP_Term) {
                    $collected[$selected_slug] = [
                        'slug'  => $selected_slug,
                        'name'  => (string) $selected_term->name,
                        'count' => 0,
                    ];
                }
            }

            $option_rows = array_values($collected);
            usort($option_rows, static function ($a, $b) {
                return strcasecmp((string) ($a['name'] ?? ''), (string) ($b['name'] ?? ''));
            });
            $options[$key] = $option_rows;
        }

        return $options;
    }
}
