"""Fixtures de pruebas del módulo CRM.

Las pruebas de servicios corren contra SQLite en memoria usando
``schema_translate_map`` para mapear los schemas ``crm``/``core`` al schema
principal de SQLite. Esto permite ejercitar la lógica de negocio sin depender
de PostgreSQL/Docker en el entorno de desarrollo local.

Nota: la validación estructural del esquema (FKs cross-schema, DDL) se hace
con la migración Alembic contra PostgreSQL en CI (``TEST_DATABASE_URL``).
"""

import os
import sys
from datetime import datetime

import pytest
from sqlalchemy import Column, Integer, String, Table, create_engine, event
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import StaticPool

BACKEND_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
if BACKEND_DIR not in sys.path:
    sys.path.insert(0, BACKEND_DIR)

from core.database import Base  # noqa: E402

# Importar los modelos registra sus tablas en Base.metadata
import api.v1.modules.crm.accounts.models  # noqa: E402,F401
import api.v1.modules.crm.activities.models  # noqa: E402,F401
import api.v1.modules.crm.addresses.models  # noqa: E402,F401
import api.v1.modules.crm.cases.models  # noqa: E402,F401
import api.v1.modules.crm.catalogs.models  # noqa: E402,F401
import api.v1.modules.crm.common.folios  # noqa: E402,F401
import api.v1.modules.crm.contacts.models  # noqa: E402,F401
import api.v1.modules.crm.documents.models  # noqa: E402,F401
import api.v1.modules.crm.leads.models  # noqa: E402,F401
import api.v1.modules.crm.opportunities.models  # noqa: E402,F401
import api.v1.modules.crm.pipelines.models  # noqa: E402,F401
import api.v1.modules.crm.quotes.models  # noqa: E402,F401
import api.v1.modules.crm.service_requests.models  # noqa: E402,F401
import api.v1.modules.crm.suppliers.models  # noqa: E402,F401
import api.v1.modules.ops.shipments.models  # noqa: E402,F401
import api.v1.modules.fin.catalogs.models  # noqa: E402,F401
import api.v1.modules.fin.concepts.models  # noqa: E402,F401
import api.v1.modules.fin.issuer.models  # noqa: E402,F401
import api.v1.modules.fin.invoices.models  # noqa: E402,F401
import api.v1.modules.fin.stamping.models  # noqa: E402,F401
from api.v1.modules.fin.catalogs.seed_data import sync_catalogs  # noqa: E402

_SCHEMA_MAP = {"crm": None, "core": None, "ops": None, "fin": None, "sat": None}

# Tabla mínima core.tenants para resolver la FK tenant_id de las tablas crm.
# En CI (PostgreSQL) la tabla real la crea la migración inicial del core.
if "core.tenants" not in Base.metadata.tables:
    Table(
        "tenants",
        Base.metadata,
        Column("id", Integer, primary_key=True),
        Column("name", String(255)),
        schema="core",
    )

TENANT_ID = 1
COMPANY_ID = 1


@pytest.fixture()
def db():
    engine = create_engine(
        "sqlite://",
        connect_args={"check_same_thread": False},
        poolclass=StaticPool,
        future=True,
    ).execution_options(schema_translate_map=_SCHEMA_MAP)

    @event.listens_for(engine, "connect")
    def _register_now(dbapi_conn, _record):
        # Soporta server_default text("now()") de los mixins de timestamp
        dbapi_conn.create_function(
            "now", 0, lambda: datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S.%f")
        )

    Base.metadata.create_all(engine)
    session_factory = sessionmaker(bind=engine, future=True)
    session = session_factory()
    # Los catálogos del SAT los siembra la migración en PostgreSQL; aquí se replica
    # con la misma función para que conceptos y emisor tengan claves que referenciar.
    sync_catalogs(session.connection())
    session.commit()
    try:
        yield session
    finally:
        session.close()
        engine.dispose()
