# #region MappingsApi [C:3] [TYPE Module] [SEMANTICS fastapi, mapping, api, mapping-create]
# @defgroup Api Module group.
#
# @BRIEF API endpoints for managing database mappings and getting suggestions.
# @LAYER     API
# @RELATION DEPENDS_ON -> [AppDependencies]
# @RELATION DEPENDS_ON -> [DatabaseModule]
# @RELATION DEPENDS_ON -> [mapping_service]
#
#


from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel, ConfigDict
from sqlalchemy.orm import Session

from ...core.database import get_db
from ...core.logger import belief_scope
from ...dependencies import get_config_manager, has_permission
from ...models.mapping import DatabaseMapping

router = APIRouter(tags=["mappings"])

# #region MappingCreate [TYPE DataClass]
# @ingroup Api
class MappingCreate(BaseModel):
    source_env_id: str
    target_env_id: str
    source_db_uuid: str
    target_db_uuid: str
    source_db_name: str
    target_db_name: str
    engine: str | None = None
# #endregion MappingCreate

# #region MappingResponse [TYPE DataClass]
# @ingroup Api
class MappingResponse(BaseModel):
    id: str
    source_env_id: str
    target_env_id: str
    source_db_uuid: str
    target_db_uuid: str
    source_db_name: str
    target_db_name: str
    engine: str | None = None

    model_config = ConfigDict(from_attributes=True)
# #endregion MappingResponse

# #region SuggestRequest [TYPE DataClass]
# @ingroup Api
class SuggestRequest(BaseModel):
    source_env_id: str
    target_env_id: str
# #endregion SuggestRequest

# #region get_mappings [TYPE Function]
# @ingroup Api
# @BRIEF List all saved database mappings.
# @PRE      db session is injected.
# @POST     Returns filtered list of DatabaseMapping records.
@router.get("", response_model=list[MappingResponse])
async def get_mappings(
    source_env_id: str | None = None,
    target_env_id: str | None = None,
    db: Session = Depends(get_db),
    _ = Depends(has_permission("plugin:mapper", "EXECUTE"))
):
    with belief_scope("get_mappings"):
        query = db.query(DatabaseMapping)
    if source_env_id:
        query = query.filter(DatabaseMapping.source_env_id == source_env_id)
    if target_env_id:
        query = query.filter(DatabaseMapping.target_env_id == target_env_id)
    return query.all()
# #endregion get_mappings

# #region create_mapping [TYPE Function]
# @ingroup Api
# @BRIEF Create or update a database mapping.
# @PRE      mapping is valid MappingCreate, db session is injected.
# @POST     DatabaseMapping created or updated in database.
@router.post("", response_model=MappingResponse)
async def create_mapping(
    mapping: MappingCreate,
    db: Session = Depends(get_db),
    _ = Depends(has_permission("plugin:mapper", "EXECUTE"))
):
    with belief_scope("create_mapping"):
        # Check if mapping already exists
        existing = db.query(DatabaseMapping).filter(
            DatabaseMapping.source_env_id == mapping.source_env_id,
            DatabaseMapping.target_env_id == mapping.target_env_id,
            DatabaseMapping.source_db_uuid == mapping.source_db_uuid
        ).first()

        if existing:
            existing.target_db_uuid = mapping.target_db_uuid
            existing.target_db_name = mapping.target_db_name
            existing.engine = mapping.engine
            db.commit()
            db.refresh(existing)
            return existing

        new_mapping = DatabaseMapping(**mapping.model_dump())
        db.add(new_mapping)
        db.commit()
        db.refresh(new_mapping)
        return new_mapping
# #endregion create_mapping

# #region suggest_mappings_api [TYPE Function]
# @ingroup Api
# @BRIEF Get suggested mappings based on fuzzy matching.
# @PRE      request is valid SuggestRequest, config_manager is injected.
# @POST     Returns mapping suggestions.
@router.post("/suggest")
async def suggest_mappings_api(
    request: SuggestRequest,
    config_manager=Depends(get_config_manager),
    _ = Depends(has_permission("plugin:mapper", "EXECUTE"))
):
    with belief_scope("suggest_mappings_api"):
        from ...services.mapping_service import MappingService
        service = MappingService(config_manager)
        try:
            return await service.get_suggestions(request.source_env_id, request.target_env_id)
        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))
# #endregion suggest_mappings_api

# #endregion MappingsApi
