<?php
/**
 * WooCommerce global product attributes — list, CRUD, and term management for ZERTI inventory.
 */

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

function zerti_product_attributes_available(): bool
{
    return class_exists('WooCommerce')
        && function_exists('wc_get_attribute_taxonomies')
        && function_exists('wc_create_attribute');
}

function zerti_product_attributes_capability(): string
{
    return 'manage_product_terms';
}

function zerti_user_can_manage_product_attributes(): bool
{
    if (current_user_can(zerti_product_attributes_capability())) {
        return true;
    }

    return current_user_can('edit_products');
}

/**
 * @return array<string, string>
 */
function zerti_product_attribute_type_choices(): array
{
    if (!function_exists('wc_get_attribute_types')) {
        return ['select' => __('Select', 'zerti')];
    }

    $choices = [];
    foreach (wc_get_attribute_types() as $slug => $label) {
        $choices[(string) $slug] = (string) $label;
    }

    return $choices !== [] ? $choices : ['select' => __('Select', 'zerti')];
}

/**
 * @return array<string, string>
 */
function zerti_product_attribute_orderby_choices(): array
{
    return [
        'menu_order' => __('Custom order', 'zerti'),
        'name' => __('Name', 'zerti'),
        'name_num' => __('Name (numeric)', 'zerti'),
        'id' => __('ID', 'zerti'),
    ];
}

function zerti_product_attribute_sanitize_type(string $value): string
{
    $choices = zerti_product_attribute_type_choices();

    return array_key_exists($value, $choices) ? $value : 'select';
}

function zerti_product_attribute_sanitize_orderby(string $value): string
{
    $choices = zerti_product_attribute_orderby_choices();

    return array_key_exists($value, $choices) ? $value : 'menu_order';
}

/**
 * Re-register attribute taxonomies after create/update (same AJAX request).
 */
function zerti_product_attributes_refresh_taxonomies(): void
{
    delete_transient('wc_attribute_taxonomies');
    if (function_exists('wc_get_attribute_taxonomies')) {
        wc_get_attribute_taxonomies();
    }
    if (class_exists('WC_Post_Types')) {
        WC_Post_Types::register_taxonomies();
    }
}

/**
 * @return array<string, mixed>|null
 */
function zerti_product_attribute_to_item(object $row): ?array
{
    if (!isset($row->attribute_id)) {
        return null;
    }

    $id = (int) $row->attribute_id;
    $name = isset($row->attribute_label) ? (string) $row->attribute_label : '';
    $slug = isset($row->attribute_name) ? (string) $row->attribute_name : '';
    $type = isset($row->attribute_type) ? (string) $row->attribute_type : 'select';
    $order_by = isset($row->attribute_orderby) ? (string) $row->attribute_orderby : 'menu_order';
    $has_archives = !empty($row->attribute_public);

    $taxonomy = function_exists('wc_attribute_taxonomy_name')
        ? wc_attribute_taxonomy_name($slug)
        : 'pa_' . $slug;

    $terms_count = 0;
    if ($taxonomy !== '' && taxonomy_exists($taxonomy)) {
        $count = wp_count_terms(['taxonomy' => $taxonomy, 'hide_empty' => false]);
        $terms_count = is_wp_error($count) ? 0 : (int) $count;
    }

    $type_choices = zerti_product_attribute_type_choices();
    $orderby_choices = zerti_product_attribute_orderby_choices();

    return [
        'id' => $id,
        'name' => $name,
        'slug' => $slug,
        'taxonomy' => $taxonomy,
        'type' => zerti_product_attribute_sanitize_type($type),
        'type_label' => $type_choices[zerti_product_attribute_sanitize_type($type)] ?? $type,
        'order_by' => zerti_product_attribute_sanitize_orderby($order_by),
        'order_by_label' => $orderby_choices[zerti_product_attribute_sanitize_orderby($order_by)] ?? $order_by,
        'has_archives' => $has_archives,
        'terms_count' => $terms_count,
    ];
}

/**
 * @return list<array<string, mixed>>
 */
function zerti_product_attributes_list(): array
{
    if (!zerti_product_attributes_available()) {
        return [];
    }

    $items = [];
    foreach (wc_get_attribute_taxonomies() as $row) {
        if (!is_object($row)) {
            continue;
        }
        $item = zerti_product_attribute_to_item($row);
        if ($item !== null) {
            $items[] = $item;
        }
    }

    usort(
        $items,
        static function (array $a, array $b): int {
            return strcasecmp((string) ($a['name'] ?? ''), (string) ($b['name'] ?? ''));
        }
    );

    return $items;
}

/**
 * @return array<string, mixed>|null
 */
function zerti_product_attribute_get(int $attribute_id): ?array
{
    if ($attribute_id < 1 || !function_exists('wc_get_attribute')) {
        return null;
    }

    $attr = wc_get_attribute($attribute_id);
    if (!$attr) {
        return null;
    }

    foreach (wc_get_attribute_taxonomies() as $row) {
        if (!is_object($row) || (int) ($row->attribute_id ?? 0) !== $attribute_id) {
            continue;
        }

        return zerti_product_attribute_to_item($row);
    }

    return null;
}

/**
 * Taxonomy slug for a global attribute ID.
 */
function zerti_product_attribute_taxonomy(int $attribute_id): string
{
    $item = zerti_product_attribute_get($attribute_id);

    return $item !== null ? (string) ($item['taxonomy'] ?? '') : '';
}

/**
 * Resolve WooCommerce global attribute ID from a pa_* taxonomy slug.
 */
function zerti_product_attribute_id_from_taxonomy(string $taxonomy): int
{
    $taxonomy = sanitize_title($taxonomy);
    if ($taxonomy === '' || !zerti_str_starts_with($taxonomy, 'pa_') || !taxonomy_exists($taxonomy)) {
        return 0;
    }
    if (!function_exists('wc_attribute_taxonomy_id_by_name')) {
        return 0;
    }

    return (int) wc_attribute_taxonomy_id_by_name(str_replace('pa_', '', $taxonomy));
}

/**
 * @return list<array<string, mixed>>
 */
function zerti_product_attribute_terms_for_taxonomy(string $taxonomy): array
{
    $attribute_id = zerti_product_attribute_id_from_taxonomy($taxonomy);

    return $attribute_id > 0 ? zerti_product_attribute_terms_list($attribute_id) : [];
}

/**
 * @return list<array<string, mixed>>
 */
function zerti_product_attribute_terms_list(int $attribute_id, string $search = ''): array
{
    $taxonomy = zerti_product_attribute_taxonomy($attribute_id);
    if ($taxonomy === '' || !taxonomy_exists($taxonomy)) {
        return [];
    }

    $args = [
        'taxonomy' => $taxonomy,
        'hide_empty' => false,
        'orderby' => 'name',
        'order' => 'ASC',
    ];
    if ($search !== '') {
        $args['search'] = $search;
    }

    $terms = get_terms($args);
    if (!is_array($terms) || is_wp_error($terms)) {
        return [];
    }

    $items = [];
    foreach ($terms as $term) {
        if (!$term instanceof WP_Term) {
            continue;
        }
        $order = (int) get_term_meta($term->term_id, 'order', true);
        $items[] = [
            'id' => (int) $term->term_id,
            'name' => $term->name,
            'slug' => $term->slug,
            'description' => $term->description,
            'count' => (int) $term->count,
            'order' => $order,
        ];
    }

    usort(
        $items,
        static function (array $a, array $b): int {
            $oa = (int) ($a['order'] ?? 0);
            $ob = (int) ($b['order'] ?? 0);
            if ($oa !== $ob) {
                return $oa <=> $ob;
            }

            return strcasecmp((string) ($a['name'] ?? ''), (string) ($b['name'] ?? ''));
        }
    );

    return $items;
}

/**
 * @param array<string, mixed> $source
 * @return array{id:int,name:string,slug:string,type:string,order_by:string,has_archives:bool}
 */
function zerti_product_attribute_payload_from_array(array $source): array
{
    $id = isset($source['id']) ? absint(wp_unslash((string) $source['id'])) : 0;
    $name = isset($source['name']) ? sanitize_text_field(wp_unslash((string) $source['name'])) : '';
    $slug = isset($source['slug']) ? sanitize_title(wp_unslash((string) $source['slug'])) : '';
    $type = isset($source['type'])
        ? zerti_product_attribute_sanitize_type(sanitize_key(wp_unslash((string) $source['type'])))
        : 'select';
    $order_by = isset($source['order_by'])
        ? zerti_product_attribute_sanitize_orderby(sanitize_key(wp_unslash((string) $source['order_by'])))
        : 'menu_order';
    $has_archives = !empty($source['has_archives']);

    return [
        'id' => $id,
        'name' => $name,
        'slug' => $slug,
        'type' => $type,
        'order_by' => $order_by,
        'has_archives' => $has_archives,
    ];
}

/**
 * @return array{id:int,name:string,slug:string,type:string,order_by:string,has_archives:bool}
 */
/**
 * @param array{id:int,name:string,slug:string,type:string,order_by:string,has_archives:bool} $payload
 * @return array{ok:bool,item?:array<string,mixed>,message?:string,code?:string}
 */
function zerti_product_attribute_save(array $payload): array
{
    if (!zerti_product_attributes_available()) {
        return ['ok' => false, 'message' => __('WooCommerce is not installed', 'zerti'), 'code' => 'woocommerce_missing'];
    }

    $name = trim($payload['name'] ?? '');
    if ($name === '') {
        return ['ok' => false, 'message' => __('Name is required', 'zerti'), 'code' => 'name_required'];
    }

    $id = (int) ($payload['id'] ?? 0);
    $slug = trim((string) ($payload['slug'] ?? ''));
    $args = [
        'name' => $name,
        'slug' => $slug,
        'type' => (string) ($payload['type'] ?? 'select'),
        'order_by' => (string) ($payload['order_by'] ?? 'menu_order'),
        'has_archives' => !empty($payload['has_archives']),
    ];

    if ($id > 0) {
        $result = wc_update_attribute($id, $args);
    } else {
        $result = wc_create_attribute($args);
    }

    if (is_wp_error($result)) {
        return [
            'ok' => false,
            'message' => $result->get_error_message(),
            'code' => (string) $result->get_error_code(),
        ];
    }

    $saved_id = is_int($result) ? $result : (int) $result;
    if ($saved_id < 1) {
        return ['ok' => false, 'message' => __('Save failed', 'zerti'), 'code' => 'save_failed'];
    }

    zerti_product_attributes_refresh_taxonomies();

    $item = zerti_product_attribute_get($saved_id);

    return $item !== null
        ? ['ok' => true, 'item' => $item]
        : ['ok' => false, 'message' => __('Save failed', 'zerti'), 'code' => 'save_failed'];
}

/**
 * @return array{ok:bool,message?:string,code?:string}
 */
function zerti_product_attribute_delete(int $attribute_id): array
{
    if ($attribute_id < 1 || !function_exists('wc_delete_attribute')) {
        return ['ok' => false, 'message' => __('Not found', 'zerti'), 'code' => 'not_found'];
    }

    if (!zerti_product_attribute_get($attribute_id)) {
        return ['ok' => false, 'message' => __('Not found', 'zerti'), 'code' => 'not_found'];
    }

    $deleted = wc_delete_attribute($attribute_id);
    if (!$deleted) {
        return ['ok' => false, 'message' => __('Delete failed', 'zerti'), 'code' => 'delete_failed'];
    }

    zerti_product_attributes_refresh_taxonomies();

    return ['ok' => true];
}

/**
 * @param array<string, mixed> $source
 * @return array{attribute_id:int,id:int,name:string,slug:string,description:string}
 */
function zerti_product_attribute_term_payload_from_array(array $source): array
{
    return [
        'attribute_id' => isset($source['attribute_id']) ? absint(wp_unslash((string) $source['attribute_id'])) : 0,
        'id' => isset($source['term_id']) ? absint(wp_unslash((string) $source['term_id'])) : 0,
        'name' => isset($source['name']) ? sanitize_text_field(wp_unslash((string) $source['name'])) : '',
        'slug' => isset($source['slug']) ? sanitize_title(wp_unslash((string) $source['slug'])) : '',
        'description' => isset($source['description']) ? wp_kses_post(wp_unslash((string) $source['description'])) : '',
    ];
}

/**
 * @return array{attribute_id:int,id:int,name:string,slug:string,description:string}
 */
/**
 * @param array{attribute_id:int,id:int,name:string,slug:string,description:string} $payload
 * @return array{ok:bool,item?:array<string,mixed>,message?:string,code?:string}
 */
function zerti_product_attribute_term_save(array $payload): array
{
    $attribute_id = (int) ($payload['attribute_id'] ?? 0);
    $taxonomy = zerti_product_attribute_taxonomy($attribute_id);
    if ($taxonomy === '' || !taxonomy_exists($taxonomy)) {
        return ['ok' => false, 'message' => __('Taxonomy missing', 'zerti'), 'code' => 'taxonomy_missing'];
    }

    $name = trim($payload['name'] ?? '');
    if ($name === '') {
        return ['ok' => false, 'message' => __('Term name is required', 'zerti'), 'code' => 'term_name_required'];
    }

    $id = (int) ($payload['id'] ?? 0);
    $slug = trim((string) ($payload['slug'] ?? ''));
    if ($slug === '') {
        $slug = sanitize_title($name);
    }

    $args = [
        'description' => (string) ($payload['description'] ?? ''),
        'slug' => $slug,
    ];

    if ($id > 0) {
        $existing = get_term($id, $taxonomy);
        if (!$existing instanceof WP_Term || is_wp_error($existing)) {
            return ['ok' => false, 'message' => __('Not found', 'zerti'), 'code' => 'not_found'];
        }
        $result = wp_update_term($id, $taxonomy, array_merge($args, ['name' => $name]));
    } else {
        $result = wp_insert_term($name, $taxonomy, $args);
    }

    if (is_wp_error($result)) {
        return [
            'ok' => false,
            'message' => $result->get_error_message(),
            'code' => (string) $result->get_error_code(),
        ];
    }

    $term_id = $id > 0 ? $id : (int) ($result['term_id'] ?? 0);
    $term = get_term($term_id, $taxonomy);
    if (!$term instanceof WP_Term || is_wp_error($term)) {
        return ['ok' => false, 'message' => __('Save failed', 'zerti'), 'code' => 'save_failed'];
    }

    $order = (int) get_term_meta($term_id, 'order', true);

    return [
        'ok' => true,
        'item' => [
            'id' => (int) $term->term_id,
            'name' => $term->name,
            'slug' => $term->slug,
            'description' => $term->description,
            'count' => (int) $term->count,
            'order' => $order,
        ],
    ];
}

/**
 * @return array{ok:bool,message?:string,code?:string}
 */
function zerti_product_attribute_term_delete(int $attribute_id, int $term_id): array
{
    $taxonomy = zerti_product_attribute_taxonomy($attribute_id);
    if ($term_id < 1 || $taxonomy === '' || !taxonomy_exists($taxonomy)) {
        return ['ok' => false, 'message' => __('Not found', 'zerti'), 'code' => 'not_found'];
    }

    $term = get_term($term_id, $taxonomy);
    if (!$term instanceof WP_Term || is_wp_error($term)) {
        return ['ok' => false, 'message' => __('Not found', 'zerti'), 'code' => 'not_found'];
    }

    $result = wp_delete_term($term_id, $taxonomy);
    if (is_wp_error($result)) {
        return [
            'ok' => false,
            'message' => $result->get_error_message(),
            'code' => (string) $result->get_error_code(),
        ];
    }
    if ($result === false) {
        return ['ok' => false, 'message' => __('Delete failed', 'zerti'), 'code' => 'delete_failed'];
    }

    return ['ok' => true];
}

function zerti_product_attribute_error_message(string $code, string $fallback = ''): string
{
    $map = [
        'name_required' => __('Attribute name is required.', 'zerti'),
        'term_name_required' => __('Term name is required.', 'zerti'),
        'not_found' => __('Attribute not found.', 'zerti'),
        'taxonomy_missing' => __('Attribute taxonomy is not available.', 'zerti'),
        'woocommerce_missing' => __('WooCommerce is not available.', 'zerti'),
        'delete_failed' => __('Delete failed.', 'zerti'),
        'save_failed' => __('Save failed.', 'zerti'),
        'invalid_product_attribute_slug_already_exists' => __('Duplicate attribute slug.', 'zerti'),
        'invalid_product_attribute_slug_too_long' => __('Attribute slug is too long.', 'zerti'),
        'invalid_product_attribute_slug_reserved_name' => __('This slug is not allowed.', 'zerti'),
    ];

    if (isset($map[$code])) {
        return $map[$code];
    }

    return $fallback !== '' ? $fallback : __('An error occurred.', 'zerti');
}
