import prisma from '../config/database';
import { AIService } from './ai.service';

export interface ParsedSearchIntent {
  rawQuery: string;
  keywords: string[];
  category?: string;
  author?: string;
  publisher?: string;
  language?: string;
  binding?: string;
  minPrice?: number;
  maxPrice?: number;
  sortBy?: 'relevance' | 'price_asc' | 'price_desc' | 'rating' | 'newest';
  correctedQuery?: string;
}

export class AISearchService {
  /**
   * AI Natural Language Smart Search with Intent Recognition & Semantic Hybrid Matching
   */
  static async smartSearch(query: string, 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: any = {
      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([
      prisma.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' },
      }),
      prisma.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
   */
  public static async parseSearchIntent(query: string): Promise<ParsedSearchIntent> {
    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 (AIService.isAIConfigured()) {
        const result = await AIService.generateJSON<ParsedSearchIntent>(
          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: any) {
      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: string) {
    const clean = query.trim().toLowerCase();
    if (clean.length < 2) return { suggestions: [], corrections: [] };

    // Common Sanskrit/Vedic phonetic aliases dictionary
    const phoneticCorrections: Record<string, string> = {
      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([
      prisma.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,
      }),
      prisma.author.findMany({
        where: { name: { contains: clean } },
        select: { id: true, name: true, slug: true },
        take: 3,
      }),
      prisma.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
   */
  private static heuristicIntentParser(query: string): ParsedSearchIntent {
    let text = query.trim();
    let maxPrice: number | undefined;
    let minPrice: number | undefined;
    let language: string | undefined;
    let binding: string | undefined;

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