# #region TranslateJobRoutesModule [C:3] [TYPE Module] [SEMANTICS fastapi, translate, api, search]
# @BRIEF Translation Job CRUD and datasource column routes.
# @LAYER API


from fastapi import Depends, HTTPException, Query, status
from sqlalchemy.orm import Session

from ....core.config_manager import ConfigManager
from ....core.database import get_db
from ....core.logger import belief_scope, logger
from ....dependencies import get_config_manager, get_current_user, has_permission
from ....plugins.translate.service import (
    TranslateJobService,
    get_datasource_columns as fetch_datasource_columns_service,
)
from ....plugins.translate.service_target_schema import validate_target_table_schema
from ....plugins.translate.service_utils import job_to_response
from ....schemas.auth import User
from ....schemas.translate import (
    DatasourceColumnsResponse,
    DuplicateJobResponse,
    TargetSchemaValidationRequest,
    TargetSchemaValidationResponse,
    TranslateJobCreate,
    TranslateJobResponse,
    TranslateJobUpdate,
)
from ._router import router

# ============================================================
# Translation Job CRUD
# ============================================================

# #region list_jobs [C:4] [TYPE Function]
# @BRIEF List all translation jobs.
# @PRE  User has translate.job.view permission.
# @POST  Returns list of translation jobs.
@router.get("/jobs", response_model=list[TranslateJobResponse])
async def list_jobs(
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
    status: str | None = Query(None),
    current_user: User = Depends(get_current_user),
    _ = Depends(has_permission("translate.job", "VIEW")),
    db: Session = Depends(get_db),
    config_manager: ConfigManager = Depends(get_config_manager),
):
    """List all translation jobs."""
    logger.reason(f"list_jobs — User: {current_user.username}", extra={"src": "translate_routes"})
    try:
        service = TranslateJobService(db, config_manager, current_user.username)
        total, jobs = service.list_jobs(
            page=page,
            page_size=page_size,
            status_filter=status,
        )
        results = []
        for job in jobs:
            dict_ids = service.get_job_dictionary_ids(job.id)
            results.append(job_to_response(job, dict_ids))
        return results
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
# #endregion list_jobs


# #region get_job [C:4] [TYPE Function]
# @BRIEF Get a single translation job by ID.
# @PRE  User has translate.job.view permission.
# @POST  Returns the translation job.
@router.get("/jobs/{job_id}", response_model=TranslateJobResponse)
async def get_job(
    job_id: str,
    current_user: User = Depends(get_current_user),
    _ = Depends(has_permission("translate.job", "VIEW")),
    db: Session = Depends(get_db),
    config_manager: ConfigManager = Depends(get_config_manager),
):
    """Get a translation job by ID."""
    logger.reason(f"get_job — Job: {job_id}, User: {current_user.username}", extra={"src": "translate_routes"})
    try:
        service = TranslateJobService(db, config_manager, current_user.username)
        job = service.get_job(job_id)
        dict_ids = service.get_job_dictionary_ids(job.id)
        return job_to_response(job, dict_ids)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
# #endregion get_job


# #region create_job [C:4] [TYPE Function]
# @BRIEF Create a new translation job.
# @PRE  User has translate.job.create permission.
# @POST  Returns the created translation job.
# @SIDE_EFFECT  Validates columns via SupersetClient; caches database_dialect.
@router.post("/jobs", response_model=TranslateJobResponse, status_code=status.HTTP_201_CREATED)
async def create_job(
    payload: TranslateJobCreate,
    current_user: User = Depends(get_current_user),
    _ = Depends(has_permission("translate.job", "CREATE")),
    db: Session = Depends(get_db),
    config_manager: ConfigManager = Depends(get_config_manager),
):
    """Create a new translation job."""
    logger.reason(f"create_job — User: {current_user.username}", extra={"src": "translate_routes"})
    try:
        service = TranslateJobService(db, config_manager, current_user.username)
        job = service.create_job(payload)
        dict_ids = service.get_job_dictionary_ids(job.id)
        return job_to_response(job, dict_ids)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(e))
# #endregion create_job


# #region update_job [C:4] [TYPE Function]
# @BRIEF Update an existing translation job.
# @PRE  User has translate.job.edit permission.
# @POST  Returns the updated translation job.
# @SIDE_EFFECT  Re-detects database_dialect if datasource changed.
@router.put("/jobs/{job_id}", response_model=TranslateJobResponse)
async def update_job(
    job_id: str,
    payload: TranslateJobUpdate,
    current_user: User = Depends(get_current_user),
    _ = Depends(has_permission("translate.job", "EDIT")),
    db: Session = Depends(get_db),
    config_manager: ConfigManager = Depends(get_config_manager),
):
    """Update a translation job."""
    logger.reason(f"update_job — Job: {job_id}, User: {current_user.username}", extra={"src": "translate_routes"})
    try:
        service = TranslateJobService(db, config_manager, current_user.username)
        job = service.update_job(job_id, payload)
        dict_ids = service.get_job_dictionary_ids(job.id)
        return job_to_response(job, dict_ids)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
# #endregion update_job


# #region delete_job [C:4] [TYPE Function]
# @BRIEF Delete a translation job.
# @PRE  User has translate.job.delete permission.
# @POST  Job is deleted.
@router.delete("/jobs/{job_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_job(
    job_id: str,
    current_user: User = Depends(get_current_user),
    _ = Depends(has_permission("translate.job", "DELETE")),
    db: Session = Depends(get_db),
    config_manager: ConfigManager = Depends(get_config_manager),
):
    """Delete a translation job."""
    logger.reason(f"delete_job — Job: {job_id}, User: {current_user.username}", extra={"src": "translate_routes"})
    try:
        service = TranslateJobService(db, config_manager, current_user.username)
        service.delete_job(job_id)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
# #endregion delete_job


# #region duplicate_job [C:4] [TYPE Function]
# @BRIEF Duplicate a translation job.
# @PRE  User has translate.job.create permission.
# @POST  Returns the duplicated job with status DRAFT.
@router.post("/jobs/{job_id}/duplicate", response_model=DuplicateJobResponse, status_code=status.HTTP_201_CREATED)
async def duplicate_job(
    job_id: str,
    current_user: User = Depends(get_current_user),
    _ = Depends(has_permission("translate.job", "CREATE")),
    db: Session = Depends(get_db),
    config_manager: ConfigManager = Depends(get_config_manager),
):
    """Duplicate a translation job."""
    logger.reason(f"duplicate_job — Job: {job_id}, User: {current_user.username}", extra={"src": "translate_routes"})
    try:
        service = TranslateJobService(db, config_manager, current_user.username)
        new_job = service.duplicate_job(job_id)
        return DuplicateJobResponse(
            id=new_job.id,
            name=new_job.name,
            message="Job duplicated successfully",
        )
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
# #endregion duplicate_job


# #region get_datasource_columns [C:4] [TYPE Function]
# @BRIEF Get column metadata and database dialect for a Superset datasource.
# @PRE User has translate.job.view permission.
# @POST Returns column list with metadata and database_dialect.
# @SIDE_EFFECT Queries Superset API for dataset detail and database info.
# @RATIONALE Dialect detection from Superset connection cached on TranslationJob at save time.
# @REJECTED Hardcoding dialect list per database — would drift from actual Superset config.
# @COMPLEXITY 4

@router.get("/datasources")
async def list_datasources(
    env_id: str = Query(..., description="Superset environment ID"),
    search: str | None = Query(None, description="Search by table name"),
    current_user: User = Depends(get_current_user),
    _ = Depends(has_permission("translate.job", "VIEW")),
    db: Session = Depends(get_db),
    config_manager: ConfigManager = Depends(get_config_manager),
):
    """List all Superset datasets available for translation jobs."""
    with belief_scope("list_datasources"):
        try:
            service = TranslateJobService(db, config_manager)
            datasets = service.fetch_available_datasources(env_id, search)
            return datasets
        except Exception as e:
            logger.explore("list_datasources failed", extra={"src": "translate_routes", "error": str(e)})
            raise HTTPException(status_code=status.HTTP_502_BAD_GATEWAY, detail=str(e))

@router.get("/datasources/{datasource_id}/columns", response_model=DatasourceColumnsResponse)
async def get_datasource_columns(
    datasource_id: int,
    env_id: str = Query(..., description="Superset environment ID"),
    current_user: User = Depends(get_current_user),
    _ = Depends(has_permission("translate.job", "VIEW")),
    config_manager: ConfigManager = Depends(get_config_manager),
):
    """Get column metadata and database dialect for a Superset datasource."""
    logger.reason(
        f"get_datasource_columns — Datasource: {datasource_id}, Env: {env_id}, User: {current_user.username}",
        extra={"src": "translate_routes"}
    )
    try:
        result = fetch_datasource_columns_service(
            datasource_id=datasource_id,
            env_id=env_id,
            config_manager=config_manager,
        )
        return result
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    except Exception as e:
        logger.explore("get_datasource_columns failed", extra={"src": "translate_routes", "error": str(e)})
        raise HTTPException(
            status_code=status.HTTP_502_BAD_GATEWAY,
            detail=f"Failed to fetch datasource columns from Superset: {e}",
        )
# #endregion get_datasource_columns


# #region check_target_schema [C:3] [TYPE Function] [SEMANTICS api,translate,validate]
# @BRIEF Проверяет схему целевой таблицы: какие колонки ожидаются, какие есть, каких не хватает.
# @RELATION DEPENDS_ON -> [validate_target_table_schema]
# @RELATION DEPENDS_ON -> [TargetSchemaValidationRequest]
# @RELATION DEPENDS_ON -> [TargetSchemaValidationResponse]
# @RATIONALE Позволяет UI показать пользователю подсказку о недостающих колонках
#   на этапе настройки джобы, до запуска перевода.
@router.post("/check-target-schema", response_model=TargetSchemaValidationResponse)
async def check_target_schema(
    payload: TargetSchemaValidationRequest,
    current_user: User = Depends(get_current_user),
    _ = Depends(has_permission("translate.job", "VIEW")),
    config_manager: ConfigManager = Depends(get_config_manager),
):
    """Check target table schema — validate expected vs actual columns for translation inserts."""
    logger.reason(
        f"check_target_schema — Table: {payload.target_schema}.{payload.target_table}, "
        f"Env: {payload.environment_id}, User: {current_user.username}",
        extra={"src": "translate_routes"},
    )
    try:
        result = validate_target_table_schema(payload, config_manager)
        return result
    except Exception as e:
        logger.explore("check_target_schema failed",
                       extra={"src": "translate_routes", "error": str(e)})
        return TargetSchemaValidationResponse(
            table_exists=False,
            error=str(e),
            all_present=False,
        )
# #endregion check_target_schema


# #endregion TranslateJobRoutesModule
