#!/usr/bin/env python3
"""
Hugo Content Search Index Generator
Extracts data from Hugo content files and creates searchable JSON indexes
"""

import os
import json
import re
from pathlib import Path
from typing import Dict, List, Optional
import logging

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

class HugoContentSearchIndexGenerator:
    def __init__(self, content_dir: str, output_dir: str):
        self.content_dir = Path(content_dir)
        self.output_dir = Path(output_dir)
        self.output_dir.mkdir(parents=True, exist_ok=True)
        
    def parse_yaml_frontmatter(self, yaml_str: str) -> Dict:
        """Simple YAML parser for Hugo frontmatter"""
        data = {}
        lines = yaml_str.strip().split('\n')
        
        for line in lines:
            line = line.strip()
            if not line or line.startswith('#'):
                continue
                
            # Match key: value pairs
            match = re.match(r'^([^:]+):\s*(.*)$', line)
            if match:
                key = match.group(1).strip()
                value = match.group(2).strip()
                
                # Handle quoted strings
                if (value.startswith('"') and value.endswith('"')) or (value.startswith("'") and value.endswith("'")):
                    value = value[1:-1]
                
                # Handle multiline strings (basic support)
                if value == '|2':
                    value = ''
                elif value and not value.startswith('|'):
                    data[key] = value
        
        return data
    
    def extract_frontmatter(self, file_path: Path) -> Optional[Dict]:
        """Extract YAML frontmatter from Hugo content file"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            
            # Find YAML frontmatter between --- markers
            match = re.match(r'^---\s*\n(.*?)\n---\s*\n', content, re.DOTALL)
            if not match:
                logger.warning(f"No frontmatter found in {file_path}")
                return None
                
            frontmatter_str = match.group(1)
            frontmatter = self.parse_yaml_frontmatter(frontmatter_str)
            
            return frontmatter
            
        except Exception as e:
            logger.error(f"Error reading {file_path}: {e}")
            return None
    
    def normalize_mpn(self, mpn: str) -> str:
        """Normalize MPN for consistent searching"""
        if not mpn:
            return ""
        # Remove spaces and convert to uppercase
        normalized = re.sub(r'\s+', '', str(mpn).upper())
        # Remove common special characters that might affect search
        normalized = re.sub(r'[-_/\\.]', '', normalized)
        return normalized
    
    def extract_sku_data(self, frontmatter: Dict, file_path: Path) -> Optional[Dict]:
        """Extract searchable data from frontmatter"""
        try:
            # Get basic fields with fallbacks
            sku = frontmatter.get('sku', '')
            mfr = frontmatter.get('mfr', '') 
            title = frontmatter.get('title', '')
            category = frontmatter.get('category', '')
            
            # Use filename as fallback for SKU if not present
            if not sku:
                sku = file_path.stem
            
            # Create searchable title if title is empty or just contains SKU
            if not title or title == sku:
                title = f"{sku} - {mfr}" if mfr else sku
            
            # Generate URL
            url = frontmatter.get('url', f"/items/{sku}/")
            
            # Extract additional searchable fields
            series = frontmatter.get('series', '')
            package = frontmatter.get('package', '')
            description = frontmatter.get('description', '')
            
            # Create comprehensive search text
            search_text = f"{sku} {mfr} {title} {category} {series} {package} {description}"
            search_text = search_text.strip()
            
            # Normalize MPN for search
            normalized_mpn = self.normalize_mpn(sku)
            
            return {
                'sku': sku,
                'mpn': sku,  # Use SKU as MPN for consistency
                'brand': mfr,
                'title': title,
                'category': category,
                'series': series,
                'package': package,
                'description': description,
                'url': url,
                'search_text': search_text.upper(),  # Pre-computed for faster search
                'normalized_mpn': normalized_mpn,
                'file_path': str(file_path.relative_to(self.content_dir))
            }
            
        except Exception as e:
            logger.error(f"Error extracting SKU data from {file_path}: {e}")
            return None
    
    def collect_all_skus(self) -> List[Dict]:
        """Collect all SKU data from Hugo content files"""
        all_skus = []
        items_dir = self.content_dir / 'items'
        
        if not items_dir.exists():
            logger.error(f"Items directory not found: {items_dir}")
            return all_skus
        
        # Process all markdown files in items directory
        md_files = list(items_dir.glob('*.md'))
        logger.info(f"Found {len(md_files)} markdown files to process")
        
        for file_path in md_files:
            frontmatter = self.extract_frontmatter(file_path)
            if not frontmatter:
                continue
                
            sku_data = self.extract_sku_data(frontmatter, file_path)
            if sku_data:
                all_skus.append(sku_data)
        
        logger.info(f"Successfully extracted {len(all_skus)} SKUs")
        return all_skus
    
    def group_by_first_letter(self, skus: List[Dict]) -> Dict[str, List[Dict]]:
        """Group SKUs by first letter of normalized MPN"""
        grouped = {}
        
        for sku in skus:
            normalized_mpn = sku['normalized_mpn']
            if not normalized_mpn:
                continue
                
            first_char = normalized_mpn[0].upper()
            
            # Group numbers together
            if first_char.isdigit():
                first_char = '0-9'
            
            # Group special characters
            if not first_char.isalnum() and first_char != '0-9':
                first_char = '_'
            
            if first_char not in grouped:
                grouped[first_char] = []
            grouped[first_char].append(sku)
        
        return grouped
    
    def generate_search_indexes(self) -> Dict:
        """Generate search index files"""
        logger.info("Collecting SKU data from Hugo content...")
        all_skus = self.collect_all_skus()
        
        if not all_skus:
            logger.error("No SKUs found to index")
            return {}
        
        logger.info("Grouping SKUs by first letter...")
        grouped = self.group_by_first_letter(all_skus)
        
        # Sort each group by MPN for better search performance
        for letter, skus in grouped.items():
            skus.sort(key=lambda x: x['mpn'])
        
        # Generate individual letter indexes
        logger.info("Generating search index files...")
        files_generated = []
        
        for letter, skus in grouped.items():
            index_data = {
                'letter': letter,
                'count': len(skus),
                'skus': skus,
                'generated_at': os.path.getmtime(__file__) if os.path.exists(__file__) else 0
            }
            
            output_file = self.output_dir / f"{letter}.json"
            with open(output_file, 'w', encoding='utf-8') as f:
                json.dump(index_data, f, ensure_ascii=False, indent=2)
            
            files_generated.append(f"{letter}.json")
            logger.info(f"Generated {output_file} with {len(skus)} SKUs")
        
        # Generate global index (lightweight)
        logger.info("Generating global index...")
        global_index = []
        for sku in all_skus:
            # Determine which file this SKU belongs to
            normalized_mpn = sku['normalized_mpn']
            if not normalized_mpn:
                file_letter = '_'
            else:
                first_char = normalized_mpn[0].upper()
                if first_char.isdigit():
                    file_letter = '0-9'
                elif not first_char.isalnum():
                    file_letter = '_'
                else:
                    file_letter = first_char
            
            global_index.append({
                'm': sku['normalized_mpn'], # Normalized MPN
                'b': sku['brand'].upper() if sku['brand'] else '', # Brand (Upper)
                'f': file_letter # File letter
            })
            
        global_index_file = self.output_dir / "_global.json"
        with open(global_index_file, 'w', encoding='utf-8') as f:
            json.dump(global_index, f, ensure_ascii=False, separators=(',', ':'))
        
        logger.info(f"Generated global index with {len(global_index)} entries")

        # Generate summary file
        summary = {
            'total_skus': len(all_skus),
            'letters': sorted(grouped.keys()),
            'files_generated': len(files_generated),
            'generated_at': os.path.getmtime(__file__) if os.path.exists(__file__) else 0
        }
        
        summary_file = self.output_dir / "_summary.json"
        with open(summary_file, 'w', encoding='utf-8') as f:
            json.dump(summary, f, ensure_ascii=False, indent=2)
        
        logger.info(f"Search index generation complete!")
        logger.info(f"Total SKUs indexed: {len(all_skus)}")
        logger.info(f"Index files generated: {len(files_generated)}")
        logger.info(f"Letters covered: {', '.join(sorted(grouped.keys()))}")
        
        return summary

def main():
    # Default paths
    script_dir = Path(__file__).parent
    content_dir = script_dir / "content"
    output_dir = script_dir / "static" / "search-index"
    
    logger.info("Hugo Content Search Index Generator")
    logger.info(f"Content directory: {content_dir}")
    logger.info(f"Output directory: {output_dir}")
    
    generator = HugoContentSearchIndexGenerator(content_dir, output_dir)
    summary = generator.generate_search_indexes()
    
    if summary:
        logger.info("✅ Search index generation successful!")
        return 0
    else:
        logger.error("❌ Search index generation failed!")
        return 1

if __name__ == "__main__":
    exit(main())