"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AISearchService = void 0;
const database_1 = __importDefault(require("../config/database"));
const ai_service_1 = require("./ai.service");
class AISearchService {
    /**
     * AI Natural Language Smart Search with Intent Recognition & Semantic Hybrid Matching
     */
    static async smartSearch(query, page = 1, limit = 20) {
        const cleanQuery = query.trim();
        if (!cleanQuery)
            return { books: [], total: 0, intent: null, page, limit };
        // 1. Extract Search Intent with AI
        const intent = await this.parseSearchIntent(cleanQuery);
        // 2. Build Dynamic Prisma Filters
        const whereConditions = {
            isActive: true,
        };
        // Filter by Price Range if parsed from query
        if (intent.maxPrice || intent.minPrice) {
            whereConditions.price = {};
            if (intent.minPrice)
                whereConditions.price.gte = intent.minPrice;
            if (intent.maxPrice)
                whereConditions.price.lte = intent.maxPrice;
        }
        // Filter by Language
        if (intent.language) {
            whereConditions.language = { contains: intent.language };
        }
        // Filter by Binding / Format
        if (intent.binding) {
            whereConditions.OR = [
                { binding: { contains: intent.binding } },
                { format: { contains: intent.binding } },
            ];
        }
        // Build Keyword Matchers across Title, Description, and ISBN
        const searchTerms = intent.keywords.length > 0 ? intent.keywords : [cleanQuery];
        const textOrFilters = searchTerms.flatMap((term) => [
            { title: { contains: term } },
            { description: { contains: term } },
            { isbn: { contains: term } },
            { sku: { contains: term } },
            { bookAuthors: { some: { author: { name: { contains: term } } } } },
            { bookCategories: { some: { category: { name: { contains: term } } } } },
            { publisher: { name: { contains: term } } },
        ]);
        if (whereConditions.OR) {
            whereConditions.AND = [{ OR: textOrFilters }];
        }
        else {
            whereConditions.OR = textOrFilters;
        }
        const [books, total] = await Promise.all([
            database_1.default.book.findMany({
                where: whereConditions,
                include: {
                    bookAuthors: { include: { author: true } },
                    bookCategories: { include: { category: true } },
                    publisher: true,
                    images: { where: { isPrimary: true }, take: 1 },
                    variants: { where: { isActive: true } },
                },
                skip: (page - 1) * limit,
                take: limit,
                orderBy: intent.sortBy === 'price_asc'
                    ? { price: 'asc' }
                    : intent.sortBy === 'price_desc'
                        ? { price: 'desc' }
                        : intent.sortBy === 'newest'
                            ? { createdAt: 'desc' }
                            : { ratingAverage: 'desc' },
            }),
            database_1.default.book.count({ where: whereConditions }),
        ]);
        return {
            query: cleanQuery,
            correctedQuery: intent.correctedQuery || cleanQuery,
            intent,
            total,
            page,
            limit,
            totalPages: Math.ceil(total / limit),
            books: books.map((b) => ({
                id: b.id,
                title: b.title,
                slug: b.slug,
                isbn: b.isbn,
                price: Number(b.price),
                discountPrice: b.discountPrice ? Number(b.discountPrice) : null,
                stock: b.stock,
                binding: b.binding,
                language: b.language,
                coverImage: b.coverImage || b.images[0]?.url || null,
                authorName: b.bookAuthors[0]?.author.name || 'Indian Author',
                categoryName: b.bookCategories[0]?.category.name || 'General',
                publisherName: b.publisher?.name || 'Standard Publisher',
                ratingAverage: Number(b.ratingAverage),
                variantsCount: b.variants.length,
            })),
        };
    }
    /**
     * Parse Search Intent with Gemini or OpenAI
     */
    static async parseSearchIntent(query) {
        const prompt = `Analyze this user bookstore search query: "${query}"
Extract search intent, keywords, language, price constraints, author, publisher, and suggest spell corrections for Indian/Sanskrit/Vedic terms.`;
        const schemaHint = `{
  "rawQuery": string,
  "keywords": string[],
  "category": string | null,
  "author": string | null,
  "publisher": string | null,
  "language": string | null,
  "binding": string | null,
  "minPrice": number | null,
  "maxPrice": number | null,
  "sortBy": "relevance" | "price_asc" | "price_desc" | "rating" | "newest",
  "correctedQuery": string | null
}`;
        try {
            if (ai_service_1.AIService.isAIConfigured()) {
                const result = await ai_service_1.AIService.generateJSON(prompt, 'You are an AI Search Intent Parser for Indian Books Worldwide. Extract structured filters from user queries.', schemaHint);
                return {
                    ...result,
                    rawQuery: query,
                    keywords: result.keywords || [query],
                };
            }
        }
        catch (err) {
            console.warn('AI Intent parsing failed, using rule-based fallback:', err.message);
        }
        // Heuristic Intent Parser Fallback
        return this.heuristicIntentParser(query);
    }
    /**
     * AI Predictive Search Suggestions & Spell Correction
     */
    static async getSearchSuggestions(query) {
        const clean = query.trim().toLowerCase();
        if (clean.length < 2)
            return { suggestions: [], corrections: [] };
        // Common Sanskrit/Vedic phonetic aliases dictionary
        const phoneticCorrections = {
            bhagwad: 'Bhagavad',
            geeta: 'Gita',
            bhagvat: 'Bhagavad',
            ramayan: 'Ramayana',
            upnishad: 'Upanishad',
            upnishads: 'Upanishads',
            ved: 'Veda',
            puran: 'Purana',
            puranas: 'Puranas',
            shankara: 'Adi Shankaracharya',
            ayurved: 'Ayurveda',
            patanjali: 'Patanjali Yoga Sutras',
            chankya: 'Chanakya Neeti',
            arthashastra: 'Kautilya Arthashastra',
            mahabharat: 'Mahabharata',
            sanskrit: 'Sanskrit',
        };
        let corrected = clean;
        Object.entries(phoneticCorrections).forEach(([wrong, right]) => {
            if (corrected.includes(wrong)) {
                corrected = corrected.replace(new RegExp(wrong, 'gi'), right);
            }
        });
        // Query matched database books & authors
        const [matchingBooks, matchingAuthors, matchingCategories] = await Promise.all([
            database_1.default.book.findMany({
                where: {
                    isActive: true,
                    OR: [{ title: { contains: clean } }, { title: { contains: corrected } }],
                },
                select: { id: true, title: true, slug: true, coverImage: true, price: true },
                take: 5,
            }),
            database_1.default.author.findMany({
                where: { name: { contains: clean } },
                select: { id: true, name: true, slug: true },
                take: 3,
            }),
            database_1.default.category.findMany({
                where: { name: { contains: clean } },
                select: { id: true, name: true, slug: true },
                take: 3,
            }),
        ]);
        const suggestions = [
            ...matchingBooks.map((b) => ({ type: 'book', title: b.title, slug: `/books/${b.slug}`, price: Number(b.price) })),
            ...matchingAuthors.map((a) => ({ type: 'author', title: a.name, slug: `/authors/${a.slug}` })),
            ...matchingCategories.map((c) => ({ type: 'category', title: c.name, slug: `/books?category=${c.slug}` })),
        ];
        return {
            query: clean,
            correctedQuery: corrected !== clean ? corrected : null,
            suggestions,
        };
    }
    /**
     * Fast rule-based intent parser for fallback
     */
    static heuristicIntentParser(query) {
        let text = query.trim();
        let maxPrice;
        let minPrice;
        let language;
        let binding;
        // Detect price filters (e.g. "under 500", "below 1000", "less than 800")
        const priceUnderMatch = text.match(/(?:under|below|less than|within|upto)\s*(?:rs\.?|₹)?\s*(\d+)/i);
        if (priceUnderMatch) {
            maxPrice = parseInt(priceUnderMatch[1], 10);
            text = text.replace(priceUnderMatch[0], '').trim();
        }
        // Detect language
        if (/sanskrit/i.test(text))
            language = 'Sanskrit';
        else if (/hindi/i.test(text))
            language = 'Hindi';
        else if (/english/i.test(text))
            language = 'English';
        else if (/bengali/i.test(text))
            language = 'Bengali';
        else if (/tamil/i.test(text))
            language = 'Tamil';
        // Detect binding
        if (/hardcover|hardback/i.test(text))
            binding = 'Hardcover';
        else if (/paperback/i.test(text))
            binding = 'Paperback';
        else if (/ebook|digital|pdf/i.test(text))
            binding = 'EBOOK';
        const tokens = text.split(/\s+/).filter((t) => t.length > 2);
        return {
            rawQuery: query,
            keywords: tokens.length > 0 ? tokens : [query],
            language,
            binding,
            maxPrice,
            minPrice,
            sortBy: 'relevance',
            correctedQuery: query,
        };
    }
}
exports.AISearchService = AISearchService;
//# sourceMappingURL=ai-search.service.js.map