# #region GitRepoLifecycleRoutes [C:3] [TYPE Module] [SEMANTICS fastapi, git, api, sync, deploy]
# @BRIEF FastAPI endpoints for Git lifecycle operations (sync, promote, deploy).
# @LAYER API


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

from src.api.routes.git_schemas import (
    DeployRequest,
    PromoteRequest,
    PromoteResponse,
)
from src.core.database import get_db
from src.core.logger import belief_scope, logger
from src.dependencies import get_config_manager, get_current_user, has_permission
from src.models.auth import User
from src.models.git import GitProvider, GitRepository

from ._deps import get_git_service
from ._helpers import (
    _apply_git_identity_from_profile,
    _get_git_config_or_404,
    _handle_unexpected_git_route_error,
)
from ._router import router


# #region sync_dashboard [C:3] [TYPE Function]
# @BRIEF Sync dashboard state from Superset to Git using the GitPlugin.
# @RELATION CALLS -> [GitPlugin]
@router.post("/repositories/{dashboard_ref}/sync")
async def sync_dashboard(
    dashboard_ref: str,
    env_id: str | None = None,
    source_env_id: str | None = None,
    config_manager=Depends(get_config_manager),
    _=Depends(has_permission("plugin:git", "EXECUTE")),
):
    with belief_scope("sync_dashboard"):
        from . import _resolve_dashboard_id_from_ref

        try:
            dashboard_id = _resolve_dashboard_id_from_ref(
                dashboard_ref, config_manager, env_id
            )
            from src.plugins.git_plugin import GitPlugin

            plugin = GitPlugin()
            return await plugin.execute(
                {
                    "operation": "sync",
                    "dashboard_id": dashboard_id,
                    "source_env_id": source_env_id,
                }
            )
        except HTTPException:
            raise
        except Exception as e:
            _handle_unexpected_git_route_error("sync_dashboard", e)
# #endregion sync_dashboard


# #region promote_dashboard [C:3] [TYPE Function]
# @BRIEF Promote changes between branches via MR or direct merge.
# @RELATION CALLS -> [GitPlugin]
@router.post("/repositories/{dashboard_ref}/promote", response_model=PromoteResponse)
async def promote_dashboard(
    dashboard_ref: str,
    payload: PromoteRequest,
    env_id: str | None = None,
    config_manager=Depends(get_config_manager),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
    _=Depends(has_permission("plugin:git", "EXECUTE")),
):
    _gs = get_git_service()
    with belief_scope("promote_dashboard"):
        from . import _resolve_dashboard_id_from_ref

        dashboard_id = _resolve_dashboard_id_from_ref(
            dashboard_ref, config_manager, env_id
        )
        db_repo = (
            db.query(GitRepository)
            .filter(GitRepository.dashboard_id == dashboard_id)
            .first()
        )
        if not db_repo:
            raise HTTPException(
                status_code=404,
                detail=f"Repository for dashboard {dashboard_ref} is not initialized",
            )
        config = _get_git_config_or_404(db, db_repo.config_id)

        from_branch = payload.from_branch.strip()
        to_branch = payload.to_branch.strip()
        if not from_branch or not to_branch:
            raise HTTPException(
                status_code=400, detail="from_branch and to_branch are required"
            )
        if from_branch == to_branch:
            raise HTTPException(
                status_code=400, detail="from_branch and to_branch must be different"
            )

        mode = (payload.mode or "mr").strip().lower()
        if mode == "direct":
            reason = (payload.reason or "").strip()
            if not reason:
                raise HTTPException(
                    status_code=400, detail="Direct promote requires non-empty reason"
                )
            logger.warning(
                "[promote_dashboard][PolicyViolation] Direct promote without MR by actor=unknown dashboard_ref=%s from=%s to=%s reason=%s",
                dashboard_ref,
                from_branch,
                to_branch,
                reason,
            )
            _apply_git_identity_from_profile(dashboard_id, db, current_user)
            result = _gs.promote_direct_merge(
                dashboard_id=dashboard_id,
                from_branch=from_branch,
                to_branch=to_branch,
            )
            return PromoteResponse(
                mode="direct",
                from_branch=from_branch,
                to_branch=to_branch,
                status=result.get("status", "merged"),
                policy_violation=True,
            )

        title = (payload.title or "").strip() or f"Promote {from_branch} -> {to_branch}"
        description = payload.description
        if config.provider == GitProvider.GITEA:
            pr = await _gs.create_gitea_pull_request(
                server_url=config.url,
                pat=config.pat,
                remote_url=db_repo.remote_url,
                from_branch=from_branch,
                to_branch=to_branch,
                title=title,
                description=description,
            )
        elif config.provider == GitProvider.GITHUB:
            pr = await _gs.create_github_pull_request(
                server_url=config.url,
                pat=config.pat,
                remote_url=db_repo.remote_url,
                from_branch=from_branch,
                to_branch=to_branch,
                title=title,
                description=description,
                draft=payload.draft,
            )
        elif config.provider == GitProvider.GITLAB:
            pr = await _gs.create_gitlab_merge_request(
                server_url=config.url,
                pat=config.pat,
                remote_url=db_repo.remote_url,
                from_branch=from_branch,
                to_branch=to_branch,
                title=title,
                description=description,
                remove_source_branch=payload.remove_source_branch,
            )
        else:
            raise HTTPException(
                status_code=501,
                detail=f"Provider {config.provider} does not support promotion API",
            )

        return PromoteResponse(
            mode="mr",
            from_branch=from_branch,
            to_branch=to_branch,
            status=pr.get("status", "opened"),
            url=pr.get("url"),
            reference_id=str(pr.get("id")) if pr.get("id") is not None else None,
            policy_violation=False,
        )
# #endregion promote_dashboard


# #region deploy_dashboard [C:3] [TYPE Function]
# @BRIEF Deploy dashboard from Git to a target environment.
# @RELATION CALLS -> [GitPlugin]
@router.post("/repositories/{dashboard_ref}/deploy")
async def deploy_dashboard(
    dashboard_ref: str,
    deploy_data: DeployRequest,
    env_id: str | None = None,
    config_manager=Depends(get_config_manager),
    _=Depends(has_permission("plugin:git", "EXECUTE")),
):
    with belief_scope("deploy_dashboard"):
        from . import _resolve_dashboard_id_from_ref

        try:
            dashboard_id = _resolve_dashboard_id_from_ref(
                dashboard_ref, config_manager, env_id
            )
            from src.plugins.git_plugin import GitPlugin

            plugin = GitPlugin()
            return await plugin.execute(
                {
                    "operation": "deploy",
                    "dashboard_id": dashboard_id,
                    "environment_id": deploy_data.environment_id,
                }
            )
        except HTTPException:
            raise
        except Exception as e:
            _handle_unexpected_git_route_error("deploy_dashboard", e)
# #endregion deploy_dashboard
# #endregion GitRepoLifecycleRoutes
