"""Indexer — batch-indexes existing Odoo records into the vector store."""

import logging

_logger = logging.getLogger(__name__)

MODEL_CONFIG = [
    {
        'model': 'op.course',
        'content_type': 'course',
        'text_field': 'name',
        'description_field': 'description',
        'metadata_fields': [],
        'course_field': 'id',
        'subject_field': 'subject_id',
    },
    {
        'model': 'encoach.resource',
        'content_type': 'resource',
        'text_field': 'name',
        'description_field': 'content',
        'metadata_fields': ['type', 'cefr_level', 'difficulty'],
        'course_field': 'course_id',
        'subject_field': 'subject_id',
        'entity_field': 'entity_id',
        'taxonomy_field': 'type',
    },
    {
        'model': 'encoach.question',
        'content_type': 'question',
        'text_field': 'stem',
        'description_field': None,
        'metadata_fields': ['question_type', 'difficulty', 'skill'],
        'subject_field': 'subject_id',
        'taxonomy_field': 'skill',
    },
    {
        'model': 'encoach.course.module',
        'content_type': 'module',
        'text_field': 'name',
        'description_field': 'description',
        'metadata_fields': ['skill'],
        'course_field': 'course_id',
        'taxonomy_field': 'skill',
    },
    {
        'model': 'encoach.ai.generation.log',
        'content_type': 'generation_log',
        'text_field': 'brief',
        'description_field': 'generated_content',
        'metadata_fields': ['course_type', 'status'],
        'taxonomy_field': 'course_type',
    },
    {
        'model': 'encoach.chapter.material',
        'content_type': 'material',
        'text_field': 'name',
        'description_field': 'description',
        'metadata_fields': ['type'],
        'course_field': 'course_id',
        'taxonomy_field': 'type',
    },
]


def _safe_id(record, field):
    if not field or not hasattr(record, field):
        return None
    val = getattr(record, field)
    if hasattr(val, 'id'):
        return val.id or None
    return int(val) if val else None


def _get_text(record, config):
    """Extract indexable text from a record."""
    parts = []
    text_field = config.get('text_field', 'name')
    if hasattr(record, text_field):
        val = getattr(record, text_field)
        if val:
            parts.append(str(val))

    desc_field = config.get('description_field')
    if desc_field and hasattr(record, desc_field):
        val = getattr(record, desc_field)
        if val:
            parts.append(str(val)[:2000])

    return ' '.join(parts).strip()


def _get_metadata(record, config):
    """Extract metadata dict from a record, including structured
    course/subject/entity/taxonomy fields used by the RAG retriever."""
    meta = {}
    for f in config.get('metadata_fields', []):
        if hasattr(record, f):
            val = getattr(record, f)
            if val:
                meta[f] = str(val) if not isinstance(val, (int, float, bool)) else val

    course_id = _safe_id(record, config.get('course_field'))
    if course_id:
        meta['course_id'] = course_id
    subject_id = _safe_id(record, config.get('subject_field'))
    if subject_id:
        meta['subject_id'] = subject_id
    entity_id = _safe_id(record, config.get('entity_field'))
    if entity_id:
        meta['entity_id'] = entity_id

    taxonomy_field = config.get('taxonomy_field')
    if taxonomy_field and hasattr(record, taxonomy_field):
        tx = getattr(record, taxonomy_field)
        if tx:
            meta['taxonomy'] = (
                str(tx.display_name) if hasattr(tx, 'display_name') else str(tx)
            )
    return meta


def index_model(env, config, batch_size=100):
    """Index all records of a single model."""
    model_name = config['model']
    Model = env.get(model_name)
    if Model is None:
        _logger.warning("Model %s not found, skipping", model_name)
        return 0

    Model = Model.sudo()

    from .embedding_service import EmbeddingService
    svc = EmbeddingService(env)

    total = Model.search_count([])
    indexed = 0
    offset = 0

    while offset < total:
        records = Model.search([], limit=batch_size, offset=offset, order='id')
        batch_data = []
        for rec in records:
            text = _get_text(rec, config)
            if text:
                batch_data.append({
                    'id': rec.id,
                    'text': text,
                    'metadata': _get_metadata(rec, config),
                })
        if batch_data:
            indexed += svc.bulk_index(config['content_type'], batch_data)
        offset += batch_size
        env.cr.commit()

    _logger.info("Indexed %d/%d records for %s", indexed, total, model_name)
    return indexed


def index_all(env, batch_size=100):
    """Index all configured models."""
    total = 0
    for config in MODEL_CONFIG:
        try:
            total += index_model(env, config, batch_size)
        except Exception:
            _logger.exception("Failed to index %s", config['model'])
    _logger.info("Total records indexed: %d", total)
    return total


def cron_reindex(env):
    """Cron entry point for periodic re-indexing."""
    _logger.info("Starting scheduled vector re-index")
    return index_all(env)
