"""Odoo model for storing vector embeddings via pgvector."""

import json
import logging
from odoo import api, models, fields

_logger = logging.getLogger(__name__)

VECTOR_DIM = 384  # all-MiniLM-L6-v2 output dimension


class EncoachEmbedding(models.Model):
    _name = 'encoach.embedding'
    _description = 'Vector Embedding'
    _order = 'create_date desc'

    content_type = fields.Selection([
        ('course', 'Course'),
        ('resource', 'Resource'),
        ('question', 'Question'),
        ('module', 'Module'),
        ('topic', 'Topic'),
        ('feedback', 'Feedback'),
        ('generation_log', 'Generation Log'),
    ], required=True, index=True)
    content_id = fields.Integer(required=True, index=True)
    content_text = fields.Text()
    metadata_json = fields.Text(default='{}')

    _content_unique = models.Constraint(
        'UNIQUE(content_type, content_id)',
        'Each content item can only have one embedding.',
    )

    @api.model
    def _auto_init(self):
        res = super()._auto_init()
        cr = self.env.cr
        cr.execute("SELECT 1 FROM pg_extension WHERE extname = 'vector'")
        if not cr.fetchone():
            try:
                cr.execute("CREATE EXTENSION IF NOT EXISTS vector")
                _logger.info("pgvector extension created")
            except Exception:
                _logger.warning(
                    "Could not create pgvector extension — run "
                    "'CREATE EXTENSION vector' as a superuser",
                    exc_info=True,
                )
                return res

        cr.execute("""
            SELECT column_name FROM information_schema.columns
            WHERE table_name = 'encoach_embedding' AND column_name = 'embedding'
        """)
        if not cr.fetchone():
            cr.execute(
                f"ALTER TABLE encoach_embedding ADD COLUMN embedding vector({VECTOR_DIM})"
            )
            cr.execute(
                "CREATE INDEX IF NOT EXISTS encoach_embedding_vec_idx "
                "ON encoach_embedding USING ivfflat (embedding vector_cosine_ops) "
                "WITH (lists = 100)"
            )
            _logger.info("Vector column and index created on encoach_embedding")
        return res

    def set_embedding(self, vector):
        """Store a vector embedding for this record."""
        self.ensure_one()
        vec_str = '[' + ','.join(str(v) for v in vector) + ']'
        self.env.cr.execute(
            "UPDATE encoach_embedding SET embedding = %s WHERE id = %s",
            (vec_str, self.id),
        )

    @api.model
    def cron_reindex(self):
        """Cron entry point for periodic re-indexing."""
        from odoo.addons.encoach_vector.services.indexer import index_all
        return index_all(self.env)

    @api.model
    def similarity_search(self, query_vector, *, content_type=None, limit=10):
        """Find similar embeddings using cosine distance."""
        vec_str = '[' + ','.join(str(v) for v in query_vector) + ']'
        where = "WHERE embedding IS NOT NULL"
        params = [vec_str, limit]
        if content_type:
            where += " AND content_type = %s"
            params = [vec_str, content_type, limit]

        query = f"""
            SELECT id, content_type, content_id, content_text, metadata_json,
                   1 - (embedding <=> %s::vector) AS similarity
            FROM encoach_embedding
            {where}
            ORDER BY embedding <=> %s::vector
            LIMIT %s
        """
        if content_type:
            self.env.cr.execute(query, (vec_str, content_type, vec_str, limit))
        else:
            self.env.cr.execute(query, (vec_str, vec_str, limit))

        results = []
        for row in self.env.cr.dictfetchall():
            metadata = {}
            try:
                metadata = json.loads(row['metadata_json'] or '{}')
            except (json.JSONDecodeError, TypeError):
                pass
            results.append({
                'id': row['id'],
                'content_type': row['content_type'],
                'content_id': row['content_id'],
                'text': row['content_text'],
                'metadata': metadata,
                'similarity': round(row['similarity'], 4),
            })
        return results
