<?php
/**
 * WooCommerce product brands taxonomy — list, tree, CRUD for ZERTI inventory.
 */

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

/**
 * Detect the active product brand taxonomy (WC core, PWB, YITH, etc.).
 */
function zerti_product_brand_taxonomy(): string
{
    $candidates = apply_filters('zerti_product_brand_taxonomies', [
        'product_brand',
        'pwb-brand',
        'yith_product_brand',
        'brand',
    ]);

    if (!is_array($candidates)) {
        $candidates = ['product_brand'];
    }

    foreach ($candidates as $tax) {
        $tax = sanitize_key((string) $tax);
        if ($tax !== '' && taxonomy_exists($tax)) {
            return $tax;
        }
    }

    return '';
}

function zerti_product_brands_available(): bool
{
    return zerti_product_brand_taxonomy() !== '';
}

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

function zerti_user_can_manage_product_brands(): bool
{
    if (current_user_can(zerti_product_brands_capability())) {
        return true;
    }

    return current_user_can('edit_products');
}

/**
 * @return array<string, mixed>|null
 */
function zerti_product_brand_to_item(WP_Term $term): ?array
{
    $taxonomy = zerti_product_brand_taxonomy();
    if ($taxonomy === '' || $term->taxonomy !== $taxonomy) {
        return null;
    }

    $thumb_id = (int) get_term_meta($term->term_id, 'thumbnail_id', true);
    $thumb_url = $thumb_id > 0 ? (string) wp_get_attachment_image_url($thumb_id, 'thumbnail') : '';

    return [
        'id' => (int) $term->term_id,
        'name' => $term->name,
        'slug' => $term->slug,
        'parent' => (int) $term->parent,
        'description' => $term->description,
        'count' => (int) $term->count,
        'order' => (int) get_term_meta($term->term_id, 'order', true),
        'thumbnail_id' => $thumb_id,
        'thumbnail_url' => $thumb_url,
        'display_type' => 'default',
    ];
}

/**
 * @return list<array<string, mixed>>
 */
function zerti_product_brands_flat_list(): array
{
    $taxonomy = zerti_product_brand_taxonomy();
    if ($taxonomy === '') {
        return [];
    }

    $terms = get_terms([
        'taxonomy' => $taxonomy,
        'hide_empty' => false,
        'orderby' => 'name',
        'order' => 'ASC',
    ]);

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

    $items = [];
    foreach ($terms as $term) {
        if (!$term instanceof WP_Term) {
            continue;
        }
        $row = zerti_product_brand_to_item($term);
        if ($row !== null) {
            $items[] = $row;
        }
    }

    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;
}

/**
 * Filter a flat brand list by search needle (name / slug substring; same rules as inventory › brands).
 *
 * @param list<array<string, mixed>> $flat
 * @return list<array<string, mixed>>
 */
function zerti_product_brands_filter_flat_by_search(array $flat, string $search): array
{
    $search = trim($search);
    if ($search === '') {
        return $flat;
    }

    $needle = mb_strtolower($search, 'UTF-8');
    if (function_exists('zerti_to_latin_digits')) {
        $needle_latin = mb_strtolower(zerti_to_latin_digits($search), 'UTF-8');
    } else {
        $needle_latin = $needle;
    }

    return array_values(array_filter(
        $flat,
        static function (array $row) use ($needle, $needle_latin): bool {
            $name = mb_strtolower((string) ($row['name'] ?? ''), 'UTF-8');
            $slug = mb_strtolower((string) ($row['slug'] ?? ''), 'UTF-8');
            if (zerti_str_contains($name, $needle) || zerti_str_contains($slug, $needle)) {
                return true;
            }
            if ($needle_latin !== $needle) {
                $name_latin = function_exists('zerti_to_latin_digits')
                    ? mb_strtolower(zerti_to_latin_digits((string) ($row['name'] ?? '')), 'UTF-8')
                    : $name;
                $slug_latin = function_exists('zerti_to_latin_digits')
                    ? mb_strtolower(zerti_to_latin_digits((string) ($row['slug'] ?? '')), 'UTF-8')
                    : $slug;

                return zerti_str_contains($name_latin, $needle_latin) || zerti_str_contains($slug_latin, $needle_latin);
            }

            return false;
        }
    ));
}

/**
 * Search product brands by name (product editor autocomplete; reads brands from DB).
 *
 * @return list<array{id:int,name:string,slug:string}>
 */
function zerti_product_brands_search_for_picker(string $term, int $limit = 20): array
{
    if (!zerti_product_brands_available()) {
        return [];
    }

    $term = trim($term);
    if ($term === '') {
        return [];
    }

    $limit = max(1, min(50, $limit));
    $matches = zerti_product_brands_filter_flat_by_search(zerti_product_brands_flat_list(), $term);

    $items = [];
    foreach ($matches as $row) {
        $items[] = [
            'id' => (int) ($row['id'] ?? 0),
            'name' => (string) ($row['name'] ?? ''),
            'slug' => (string) ($row['slug'] ?? ''),
        ];
        if (count($items) >= $limit) {
            break;
        }
    }

    return $items;
}

/**
 * @param list<array<string, mixed>> $flat
 * @return list<array<string, mixed>>
 */
function zerti_product_brands_build_tree(array $flat): array
{
    $by_parent = [];
    foreach ($flat as $row) {
        $parent = (int) ($row['parent'] ?? 0);
        if (!isset($by_parent[$parent])) {
            $by_parent[$parent] = [];
        }
        $by_parent[$parent][] = $row;
    }

    $walk = static function (int $parent_id) use (&$walk, $by_parent): array {
        $nodes = $by_parent[$parent_id] ?? [];
        $out = [];
        foreach ($nodes as $node) {
            $id = (int) ($node['id'] ?? 0);
            $node['children'] = $walk($id);
            $out[] = $node;
        }

        return $out;
    };

    return $walk(0);
}

/**
 * @return list<int>
 */
function zerti_product_brand_descendant_ids(int $term_id): array
{
    $taxonomy = zerti_product_brand_taxonomy();
    if ($term_id < 1 || $taxonomy === '') {
        return [];
    }

    $children = get_terms([
        'taxonomy' => $taxonomy,
        'hide_empty' => false,
        'parent' => $term_id,
        'fields' => 'ids',
    ]);
    if (!is_array($children) || is_wp_error($children)) {
        return [];
    }

    $ids = [];
    foreach ($children as $child_id) {
        $child_id = (int) $child_id;
        if ($child_id < 1) {
            continue;
        }
        $ids[] = $child_id;
        $ids = array_merge($ids, zerti_product_brand_descendant_ids($child_id));
    }

    return $ids;
}

/**
 * @return list<array{id:int,label:string,depth:int}>
 */
function zerti_product_brand_parent_options(int $exclude_term_id = 0): array
{
    $flat = zerti_product_brands_flat_list();
    $exclude = [];
    if ($exclude_term_id > 0) {
        $exclude[$exclude_term_id] = true;
        foreach (zerti_product_brand_descendant_ids($exclude_term_id) as $desc_id) {
            $exclude[$desc_id] = true;
        }
    }

    $tree = zerti_product_brands_build_tree($flat);
    $options = [
        [
            'id' => 0,
            'label' => __('— No parent (root brand) —', 'zerti'),
            'depth' => 0,
        ],
    ];

    $walk = static function (array $nodes, int $depth) use (&$walk, &$options, $exclude): void {
        foreach ($nodes as $node) {
            $id = (int) ($node['id'] ?? 0);
            if ($id < 1 || isset($exclude[$id])) {
                continue;
            }
            $prefix = $depth > 0 ? str_repeat('— ', $depth) : '';
            $options[] = [
                'id' => $id,
                'label' => $prefix . (string) ($node['name'] ?? ''),
                'depth' => $depth,
            ];
            if (!empty($node['children']) && is_array($node['children'])) {
                $walk($node['children'], $depth + 1);
            }
        }
    };

    $walk($tree, 0);

    return $options;
}

function zerti_product_brand_validate_parent(int $term_id, int $parent_id): bool
{
    $taxonomy = zerti_product_brand_taxonomy();
    if ($taxonomy === '') {
        return false;
    }
    if ($parent_id < 1) {
        return true;
    }
    if ($term_id > 0 && $parent_id === $term_id) {
        return false;
    }
    if ($term_id > 0) {
        $blocked = zerti_product_brand_descendant_ids($term_id);
        if (in_array($parent_id, $blocked, true)) {
            return false;
        }
    }

    $parent = get_term($parent_id, $taxonomy);

    return $parent instanceof WP_Term && !is_wp_error($parent);
}

/**
 * @param array<string, mixed> $source
 * @return array{id:int,name:string,slug:string,parent:int,description:string,display_type:string,thumbnail_id:int,order:int}
 */
function zerti_product_brand_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'])) : '';
    $parent = isset($source['parent']) ? absint(wp_unslash((string) $source['parent'])) : 0;
    $description = isset($source['description']) ? wp_kses_post(wp_unslash((string) $source['description'])) : '';
    $thumbnail_id = isset($source['thumbnail_id']) ? absint(wp_unslash((string) $source['thumbnail_id'])) : 0;

    return [
        'id' => $id,
        'name' => $name,
        'slug' => $slug,
        'parent' => $parent,
        'description' => $description,
        'display_type' => 'default',
        'thumbnail_id' => $thumbnail_id,
        'order' => 0,
    ];
}

/**
 * @return array{id:int,name:string,slug:string,parent:int,description:string,display_type:string,thumbnail_id:int,order:int}
 */
/**
 * @param array{id:int,name:string,slug:string,parent:int,description:string,display_type:string,thumbnail_id:int,order:int} $payload
 * @return array{ok:bool,item?:array<string,mixed>,message?:string,code?:string}
 */
function zerti_product_brand_save(array $payload): array
{
    $taxonomy = zerti_product_brand_taxonomy();
    if ($taxonomy === '') {
        return ['ok' => false, 'message' => __('Taxonomy missing', 'zerti'), 'code' => 'taxonomy_missing'];
    }

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

    $id = (int) ($payload['id'] ?? 0);
    $parent = (int) ($payload['parent'] ?? 0);
    if (!zerti_product_brand_validate_parent($id, $parent)) {
        return ['ok' => false, 'message' => __('Invalid parent', 'zerti'), 'code' => 'invalid_parent'];
    }

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

    $args = [
        'description' => (string) ($payload['description'] ?? ''),
        'parent' => $parent,
        '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);
    if ($term_id < 1) {
        return ['ok' => false, 'message' => __('Save failed', 'zerti'), 'code' => 'save_failed'];
    }

    $thumb_id = (int) ($payload['thumbnail_id'] ?? 0);
    if ($thumb_id > 0 && !wp_attachment_is_image($thumb_id)) {
        $thumb_id = 0;
    }
    if ($thumb_id > 0) {
        update_term_meta($term_id, 'thumbnail_id', $thumb_id);
    } else {
        delete_term_meta($term_id, 'thumbnail_id');
    }

    $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'];
    }

    $item = zerti_product_brand_to_item($term);

    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_brand_delete(int $term_id): array
{
    $taxonomy = zerti_product_brand_taxonomy();
    if ($term_id < 1 || $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_brand_error_message(string $code, string $fallback = ''): string
{
    $map = [
        'name_required' => __('Brand name is required.', 'zerti'),
        'invalid_parent' => __('Invalid parent brand.', 'zerti'),
        'not_found' => __('Brand not found.', 'zerti'),
        'taxonomy_missing' => __('Product brand taxonomy is not available. Enable brands in WooCommerce.', 'zerti'),
        'delete_failed' => __('Could not delete brand.', 'zerti'),
        'save_failed' => __('Could not save brand.', 'zerti'),
        'term_exists' => __('Duplicate brand name or slug.', 'zerti'),
    ];

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

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