<?php

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

class Niwa_AI_Admin_Product_Target_Resolver {
    private $memory_searcher;

    public function __construct( $memory_searcher = null ) {
        $this->memory_searcher = $memory_searcher;
    }

    public function resolve_products( $query, $statuses = array(), $limit = 5, $context = array() ) {
        $query    = trim( (string) $query );
        $limit    = max( 1, min( 12, intval( $limit ) ) );
        $statuses = $this->normalize_statuses( $statuses );
        $context  = is_array( $context ) ? $context : array();

        if ( '' === $query ) {
            return array();
        }

        $context_hits = $this->resolve_from_context( $query, $statuses, $limit, $context );
        if ( ! empty( $context_hits ) ) {
            return $context_hits;
        }

        $candidates = array();

        if ( ctype_digit( $query ) ) {
            $this->append_candidate( $candidates, intval( $query ), 1.0, 'post_id', $statuses );
        }

        if ( function_exists( 'wc_get_product_id_by_sku' ) ) {
            $sku_id = intval( wc_get_product_id_by_sku( $query ) );
            if ( $sku_id > 0 ) {
                $this->append_candidate( $candidates, $sku_id, 0.99, 'sku', $statuses );
            }
        }

        foreach ( $this->build_query_variants( $query ) as $variant ) {
            $rows = $this->memory_searcher && method_exists( $this->memory_searcher, 'search' )
                ? $this->memory_searcher->search( $variant, max( $limit * 4, 8 ), array( 'post_type' => 'product' ) )
                : array();
            foreach ( (array) $rows as $row ) {
                $post_id = isset( $row['post_id'] ) ? intval( $row['post_id'] ) : 0;
                $score   = isset( $row['_score'] ) ? floatval( $row['_score'] ) : 0.0;
                $this->append_candidate( $candidates, $post_id, $score, 'memory', $statuses, $row );
            }
        }

        usort(
            $candidates,
            function ( $left, $right ) {
                return floatval( isset( $right['score'] ) ? $right['score'] : 0 ) <=> floatval( isset( $left['score'] ) ? $left['score'] : 0 );
            }
        );

        return array_slice( $candidates, 0, $limit );
    }

    public function resolve_best_product( $query, $statuses = array(), $context = array() ) {
        $candidates = $this->resolve_products( $query, $statuses, 3, $context );
        if ( empty( $candidates ) ) {
            return array();
        }

        $best  = $candidates[0];
        $score = floatval( isset( $best['score'] ) ? $best['score'] : 0 );

        if ( $score >= 0.9 ) {
            $best['match_confidence'] = 'high';
        } elseif ( $score >= 0.55 ) {
            $best['match_confidence'] = 'medium';
        } else {
            $best['match_confidence'] = 'low';
            $best['match_warning']    = 'Nisam potpuno sigurna da je ovo pravi proizvod. Potvrdi pre izmene.';
        }

        if ( ! empty( $candidates[1] ) ) {
            $gap = $score - floatval( isset( $candidates[1]['score'] ) ? $candidates[1]['score'] : 0 );
            if ( $gap < 0.08 ) {
                $ambiguity_warning = 'Postoji vise slicnih rezultata. Potrebna je kratka potvrda pravog proizvoda.';
                if ( ! empty( $best['match_warning'] ) ) {
                    $best['match_warning'] .= ' ' . $ambiguity_warning;
                } else {
                    $best['match_warning'] = $ambiguity_warning;
                }
            }
        }

        $best['candidates'] = $candidates;

        return $best;
    }

    private function resolve_from_context( $query, $statuses, $limit, $context ) {
        $normalized = $this->normalize_text( $query );
        $records    = isset( $context['recent_product_context'] ) && is_array( $context['recent_product_context'] ) ? $context['recent_product_context'] : array();
        if ( empty( $records ) ) {
            return array();
        }

        $latest = end( $records );
        if ( ! is_array( $latest ) ) {
            return array();
        }

        $candidates = isset( $latest['candidates'] ) && is_array( $latest['candidates'] ) ? array_values( $latest['candidates'] ) : array();
        if ( empty( $candidates ) ) {
            return array();
        }

        $index = null;
        if ( in_array( $normalized, array( 'prvi', 'prva', 'prvo', 'first', '1' ), true ) ) {
            $index = 0;
        } elseif ( in_array( $normalized, array( 'drugi', 'druga', 'drugo', 'second', '2' ), true ) ) {
            $index = 1;
        } elseif ( in_array( $normalized, array( 'treci', 'treca', 'trece', 'third', '3' ), true ) ) {
            $index = 2;
        } elseif ( in_array( $normalized, array( 'taj', 'ta', 'to', 'isti', 'ista', 'isto', 'ovaj', 'ovu', 'ovog', 'njega', 'njemu', 'njoj' ), true ) ) {
            $index = 0;
        }

        if ( null === $index || empty( $candidates[ $index ]['post_id'] ) ) {
            return array();
        }

        $selected = array();
        $this->append_candidate(
            $selected,
            intval( $candidates[ $index ]['post_id'] ),
            1.0,
            'session_context',
            $statuses
        );

        return array_slice( $selected, 0, $limit );
    }

    private function append_candidate( &$candidates, $post_id, $score, $source, $statuses, $row = array() ) {
        $post_id = intval( $post_id );
        if ( $post_id <= 0 ) {
            return;
        }

        $post = get_post( $post_id );
        if ( ! $post || 'product' !== (string) $post->post_type ) {
            return;
        }

        if ( ! empty( $statuses ) && ! in_array( (string) $post->post_status, $statuses, true ) ) {
            return;
        }

        $product = function_exists( 'wc_get_product' ) ? wc_get_product( $post_id ) : false;
        if ( ! $product ) {
            return;
        }

        $key = 'p' . $post_id;
        $entry = array(
            'post_id'      => $post_id,
            'post_title'   => (string) $post->post_title,
            'post_status'  => (string) $post->post_status,
            'post_name'    => (string) $post->post_name,
            'product_type' => method_exists( $product, 'get_type' ) ? (string) $product->get_type() : '',
            'sku'          => method_exists( $product, 'get_sku' ) ? (string) $product->get_sku() : '',
            'score'        => floatval( $score ),
            'source'       => (string) $source,
            'memory_row'   => $row,
        );

        if ( isset( $candidates[ $key ] ) && floatval( $candidates[ $key ]['score'] ) >= floatval( $entry['score'] ) ) {
            return;
        }

        $candidates[ $key ] = $entry;
    }

    private function build_query_variants( $query ) {
        $variants   = array();
        $variants[] = trim( (string) $query );

        $normalized = $this->normalize_text( $query );
        if ( '' !== $normalized && $normalized !== trim( (string) $query ) ) {
            $variants[] = $normalized;
        }

        return array_values( array_unique( array_filter( array_map( 'trim', $variants ) ) ) );
    }

    private function normalize_statuses( $statuses ) {
        $default = array( 'publish', 'private', 'draft', 'pending', 'future', 'trash' );
        if ( empty( $statuses ) || ! is_array( $statuses ) ) {
            return $default;
        }

        $normalized = array();
        foreach ( $statuses as $status ) {
            $status = sanitize_key( (string) $status );
            if ( in_array( $status, $default, true ) ) {
                $normalized[] = $status;
            }
        }

        return ! empty( $normalized ) ? array_values( array_unique( $normalized ) ) : $default;
    }

    private function normalize_text( $text ) {
        $text = trim( (string) $text );
        if ( '' === $text ) {
            return '';
        }

        if ( function_exists( 'remove_accents' ) ) {
            $text = remove_accents( $text );
        }

        $text = mb_strtolower( $text );
        $text = preg_replace( '/[^a-z0-9]+/u', ' ', $text );
        $text = preg_replace( '/\s+/', ' ', $text );
        return trim( (string) $text );
    }
}
