content: from fastapi import APIRouter, Depends, HTTPException, Request
  from sqlalchemy.orm import Session
  from starlette.config import Config
  from starlette.responses import RedirectResponse
  from typing import Dict, Any, Optional
  import hmac
  import hashlib
  import base64
  import json
  import time
  from app.modules.utils.logger import setup_logger
  from app.modules.integrations import hash_user_id
  
  import urllib.parse
  import jwt
  
  from app.core.database import get_db
  from app.api.router import get_api_key_user
  from app.modules.auth.auth_service import AuthService
  
  from .sentry_oauth_v2 import SentryOAuthV2
  from .linear_oauth import LinearOAuth
  from .jira_oauth import JiraOAuth
  from .confluence_oauth import ConfluenceOAuth
  from .integrations_service import IntegrationsService
  from .integrations_schema import (
      OAuthInitiateRequest,
      OAuthStatusResponse,
      SentryIntegrationStatus,
      SentrySaveRequest,
      SentrySaveResponse,
      LinearIntegrationStatus,
      LinearSaveRequest,
      LinearSaveResponse,
      JiraIntegrationStatus,
      JiraSaveRequest,
      JiraSaveResponse,
      ConfluenceIntegrationStatus,
      ConfluenceSaveRequest,
      ConfluenceSaveResponse,
      IntegrationCreateRequest,
      IntegrationUpdateRequest,
      IntegrationResponse,
      IntegrationListResponse,
      IntegrationType,
      IntegrationStatus,
      IntegrationSaveRequest,
      IntegrationSaveResponse,
  )
  
  
  logger = setup_logger(__name__)
  router = APIRouter(prefix="/integrations", tags=["integrations"])
  
  
  def sanitize_headers(headers: Dict[str, str]) -> Dict[str, str]:
      """Remove or redact sensitive header keys"""
      sensitive_keys = {"authorization", "cookie", "set-cookie", "signature", "token"}
      sanitized = {}
      for key, value in headers.items():
          key_lower = key.lower()
          if any(sensitive in key_lower for sensitive in sensitive_keys):
              sanitized[key] = "[REDACTED]"
          else:
              sanitized[key] = value
      return sanitized
  
  
  def truncate_content(content: str, max_length: int = 200) -> str:
      """Truncate content to max_length with ellipsis"""
      if len(content) <= max_length:
          return content
      return content[:max_length] + "..."
  
  
  def get_params_summary(params: Dict[str, Any]) -> Dict[str, Any]:
      """Get a summary of params with keys and truncated values"""
      return {
          "keys": list(params.keys()),
          "count": len(params),
          "preview": {k: truncate_content(str(v)) for k, v in list(params.items())[:5]},
      }
  
  
  def get_body_summary(body_text: str) -> Dict[str, Any]:
      """Get a summary of body with length and truncated preview"""
      return {"length": len(body_text), "preview": truncate_content(body_text)}
  
  
  def get_sentry_oauth() -> SentryOAuthV2:
      """Dependency to get Sentry OAuth integration instance"""
      config = Config()
      return SentryOAuthV2(config)
  
  
  def get_linear_oauth() -> LinearOAuth:
      """Dependency to get Linear OAuth integration instance"""
      config = Config()
      return LinearOAuth(config)
  
  
  def get_jira_oauth() -> JiraOAuth:
      """Dependency to get Jira OAuth integration instance"""
      config = Config()
      return JiraOAuth(config)
  
  
  def get_confluence_oauth() -> ConfluenceOAuth:
      """Dependency to get Confluence OAuth integration instance"""
      config = Config()
      return ConfluenceOAuth(config)
  
  
  def get_integrations_service(db: Session = Depends(get_db)) -> IntegrationsService:
      """Dependency to get integrations service instance with database session"""
      return IntegrationsService(db)
  
  
  def _sign_oauth_state(raw_state: str | None, expires: int = 600) -> str | None:
      """Sign a state string with HMAC to protect against tampering.
  
      Returns a token of the form: base64(payload).hex(hmac)
      payload is JSON: {"u": <raw_state>, "e": <expiry_ts>} encoded in utf-8 then base64-url-safe.
      If raw_state is None or empty, returns None.
      """
      if not raw_state:
          return None
  
      config = Config()
      secret = config("OAUTH_STATE_SECRET", default="")
      if not secret:
          # If no secret configured, avoid signing (dev fallback)
          return raw_state
  
      expiry = int(time.time()) + int(expires)
      payload = {"u": raw_state, "e": expiry}
      payload_json = json.dumps(payload, separators=(",", ":"))
      payload_b64 = base64.urlsafe_b64encode(payload_json.encode("utf-8")).decode("utf-8")
      sig = hmac.new(
          secret.encode("utf-8"), payload_b64.encode("utf-8"), hashlib.sha256
      ).hexdigest()
      return f"{payload_b64}.{sig}"
  
  
  def _verify_oauth_state(token: str | None) -> Optional[str]:
      """Verify signed state token and return the embedded user_id (raw_state).
  
      Returns None if verification fails. If no secret configured, returns token unchanged.
      """
      if not token:
          return None
  
      config = Config()
      secret = config("OAUTH_STATE_SECRET", default="")
      if not secret:
          # No secret configured – assume token is raw state
          return token
  
      try:
          if "." not in token:
              return None
          payload_b64, sig = token.rsplit(".", 1)
          expected = hmac.new(
              secret.encode("utf-8"), payload_b64.encode("utf-8"), hashlib.sha256
          ).hexdigest()
          if not hmac.compare_digest(sig, expected):
              return None
          payload_json = base64.urlsafe_b64decode(payload_b64.encode("utf-8")).decode(
              "utf-8"
          )
          payload = json.loads(payload_json)
          expiry = int(payload.get("e", 0))
          if int(time.time()) > expiry:
              return None
          return payload.get("u")
      except Exception:
          return None
  
  
  @router.post("/sentry/initiate")
  async def initiate_sentry_oauth(
      request: OAuthInitiateRequest,
      sentry_oauth: SentryOAuthV2 = Depends(get_sentry_oauth),
  ) -> Dict[str, Any]:
      """Initiate Sentry OAuth flow"""
      try:
          # Log the OAuth initiation details
          logger.info("=== OAuth Initiation Debug ===")
          logger.info(
              "OAuth parameters", redirect_uri=request.redirect_uri, state=request.state
          )
  
          # Generate authorization URL. Sign the state to prevent tampering.
          signed_state = (
              _sign_oauth_state(request.state)
              if getattr(request, "state", None)
              else None
          )
          auth_url = sentry_oauth.get_authorization_url(
              redirect_uri=request.redirect_uri, state=signed_state
          )
  
          logger.info("Generated authorization URL for Sentry OAuth")
  
          return {
              "status": "success",
              "authorization_url": auth_url,
              "message": "OAuth flow initiated successfully",
              "debug_info": {
                  "redirect_uri": request.redirect_uri,
                  "state": request.state,
                  "auth_url": auth_url,
              },
          }
      except Exception as e:
          logger.exception("OAuth initiation failed")
          raise HTTPException(
              status_code=500, detail=f"Failed to initiate OAuth flow: {str(e)}"
          )
  
  
  @router.get("/sentry/callback")
  async def sentry_oauth_callback(
      request: Request,
      sentry_oauth: SentryOAuthV2 = Depends(get_sentry_oauth),
  ) -> OAuthStatusResponse:
      """Handle Sentry OAuth callback. Uses signed state to identify user."""
      try:
          # Extract and verify state to get user_id
          state = request.query_params.get("state")
          user_id = _verify_oauth_state(state)
          if not user_id:
              raise HTTPException(
                  status_code=400, detail="Invalid or missing OAuth state"
              )
  
          result = sentry_oauth.handle_callback(request, user_id)
          return OAuthStatusResponse(**result)
      except HTTPException:
          raise
      except Exception as e:
          raise HTTPException(status_code=400, detail=f"OAuth callback failed: {str(e)}")
  
  
  @router.get("/sentry/status/{user_id}")
  async def get_sentry_status(
      user_id: str,
      sentry_oauth: SentryOAuthV2 = Depends(get_sentry_oauth),
      user: dict = Depends(AuthService.check_auth),
  ) -> SentryIntegrationStatus:
      """Get Sentry integration status for a user"""
      # Verify the authenticated user matches the requested user_id
      if user["user_id"] != user_id:
          raise HTTPException(
              status_code=403, detail="Cannot access other users' integration status"
          )
  
      user_info = sentry_oauth.get_user_info(user_id)
  
      if not user_info:
          return SentryIntegrationStatus(user_id=user_id, is_connected=False)
  
      return SentryIntegrationStatus(
          user_id=user_id,
          is_connected=True,
          scope=user_info.get("scope"),
          expires_at=user_info.get("expires_at"),
      )
  
  
  @router.delete("/sentry/revoke/{user_id}")
  async def revoke_sentry_access(
      user_id: str,
      sentry_oauth: SentryOAuthV2 = Depends(get_sentry_oauth),
      user: dict = Depends(AuthService.check_auth),
  ) -> Dict[str, Any]:
      """Revoke Sentry OAuth access for a user"""
      # Verify the authenticated user matches the requested user_id
      if user["user_id"] != user_id:
          raise HTTPException(
              status_code=403, detail="Cannot revoke other users' integrations"
          )
  
      success = sentry_oauth.revoke_access(user_id)
  
      if success:
          return {
              "status": "success",
              "message": "Sentry access revoked successfully",
              "user_id": user_id,
          }
      else:
          raise HTTPException(status_code=500, detail="Failed to revoke Sentry access")
  
  
  @router.get("/sentry/authorize")
  async def sentry_authorize(
      request: Request, sentry_oauth: SentryOAuthV2 = Depends(get_sentry_oauth)
  ) -> RedirectResponse:
      """Direct authorization endpoint that redirects to Sentry OAuth"""
      try:
          # Get redirect URI from query params or use default
          redirect_uri = request.query_params.get(
              "redirect_uri", "http://localhost:3000/integrations/sentry/callback"
          )
  
          # Generate authorization URL
          auth_url = sentry_oauth.get_authorization_url(redirect_uri=redirect_uri)
  
          # Redirect to Sentry OAuth
          return RedirectResponse(url=auth_url)
  
      except Exception as e:
          raise HTTPException(
              status_code=500, detail=f"Failed to redirect to OAuth: {str(e)}"
          )
  
  
  @router.get("/sentry/redirect")
  async def sentry_redirect_webhook(request: Request) -> Dict[str, Any]:
      """Handle Sentry webhook redirect requests"""
      try:
          # Log the incoming request details
          logger.info("Sentry webhook redirect received")
          logger.info("Request details", method=request.method, url=str(request.url))
          sanitized_headers = sanitize_headers(dict(request.headers))
          logger.debug("Request headers", headers=sanitized_headers)
  
          # Get query parameters
          query_params = dict(request.query_params)
          params_summary = get_params_summary(query_params)
          logger.info(
              "Query parameters",
              params_keys=params_summary["keys"],
              params_count=params_summary["count"],
          )
          logger.debug("Query parameters", params_summary=params_summary)
  
          # Try to get request body if it exists
          try:
              body = await request.body()
              if body:
                  body_text = (
                      body.decode("utf-8") if isinstance(body, bytes) else str(body)
                  )
                  body_summary = get_body_summary(body_text)
                  logger.info("Request body received", body_length=body_summary["length"])
                  logger.debug(
                      "Request body preview", body_preview=body_summary["preview"]
                  )
              else:
                  logger.info("Request body: (empty)")
          except Exception as e:
              logger.warning("Could not read request body", error=str(e))
  
          # Log form data if present
          try:
              form_data = await request.form()
              if form_data:
                  form_dict = {k: str(v) for k, v in form_data.items()}
                  form_summary = get_params_summary(form_dict)
                  logger.info(
                      "Form data received",
                      form_fields=form_summary["keys"],
                      form_count=form_summary["count"],
                  )
                  logger.debug("Form data summary", form_summary=form_summary)
          except Exception as e:
              logger.debug("No form data present", error=str(e))
  
          return {
              "status": "success",
              "message": "Sentry webhook redirect logged successfully",
              "logged_at": time.time(),
          }
  
      except Exception as e:
          logger.exception("Error processing Sentry webhook redirect")
          raise HTTPException(
              status_code=500,
              detail=f"Failed to process Sentry webhook redirect: {str(e)}",
          )
  
  
  @router.get("/linear/redirect")
  async def linear_oauth_redirect(
      request: Request, linear_oauth: LinearOAuth = Depends(get_linear_oauth)
  ) -> RedirectResponse:
      """Direct authorization endpoint that redirects to Linear OAuth"""
      try:
          # Check if this is actually a callback request (has code parameter)
          if request.query_params.get("code"):
              raise HTTPException(
                  status_code=400,
                  detail="This endpoint is for OAuth initiation, not callback. Linear should redirect to /api/v1/integrations/linear/callback with the authorization code.",
              )
          # Get redirect URI from query params or construct from current request
          redirect_uri = request.query_params.get(
              "redirect_uri",
              f"https://{request.url.hostname}/api/v1/integrations/linear/callback",
          )
  
          # Get state parameter if provided
          state = request.query_params.get("state")
          signed_state = _sign_oauth_state(state) if state else None
  
          # Get scope parameter if provided (default to read)
          scope = request.query_params.get("scope", "read")
  
          # Generate authorization URL
          auth_url = linear_oauth.get_authorization_url(
              redirect_uri=redirect_uri, state=signed_state, scope=scope
          )
  
          # Redirect to Linear OAuth
          return RedirectResponse(url=auth_url)
  
      except Exception as e:
          raise HTTPException(
              status_code=500, detail=f"Failed to redirect to Linear OAuth: {str(e)}"
          )
  
  
  @router.get("/linear/callback")
  async def linear_oauth_callback(
      request: Request,
      linear_oauth: LinearOAuth = Depends(get_linear_oauth),
  ):
      """Handle Linear OAuth callback"""
      try:
          # Extract OAuth parameters
          code = request.query_params.get("code")
          state = request.query_params.get("state")
          error = request.query_params.get("error")
          error_description = request.query_params.get("error_description")
  
          # Verify signed state to get user_id
          user_id = _verify_oauth_state(state)
          if not user_id:
              raise HTTPException(
                  status_code=400, detail="Invalid or missing OAuth state"
              )
  
          # If we have an authorization code, exchange it for tokens and save to database
          if code:
              try:
                  # Get the integrations service to save the integration
                  from app.core.database import SessionLocal
  
                  db = SessionLocal()
                  integrations_service = IntegrationsService(db)
  
                  # Create a LinearSaveRequest with the authorization code
                  from .integrations_schema import LinearSaveRequest
                  from datetime import datetime
  
                  # Always use HTTPS in production
                  save_request = LinearSaveRequest(
                      code=code,
                      redirect_uri=f"https://{request.url.hostname}/api/v1/integrations/linear/callback",
                      instance_name="Linear Integration",  # Will be updated with org name in service
                      integration_type="linear",
                      timestamp=datetime.utcnow().isoformat() + "Z",
                  )
  
                  # Save the integration (this will exchange code for tokens)
                  save_result = await integrations_service.save_linear_integration(
                      save_request,
                      user_id,
                  )
  
                  db.close()
  
                  # Redirect to frontend with success
                  config = Config()
                  frontend_url = config("FRONTEND_URL", default="http://localhost:3000")
  
                  # Ensure frontend_url has protocol
                  if frontend_url and not frontend_url.startswith(
                      ("http://", "https://")
                  ):
                      frontend_url = f"https://{frontend_url}"
  
                  redirect_url = f"{frontend_url}/integrations/linear/redirect?success=true&integration_id={save_result.get('integration_id')}&user_name={save_result.get('user_name', '')}"
  
                  return RedirectResponse(url=redirect_url)
  
              except Exception as e:
                  logger.exception("Failed to save Linear integration")
  
                  # Redirect to frontend with error
                  config = Config()
                  frontend_url = config("FRONTEND_URL", default="http://localhost:3000")
  
                  # Ensure frontend_url has protocol
                  if frontend_url and not frontend_url.startswith(
                      ("http://", "https://")
                  ):
                      frontend_url = f"https://{frontend_url}"
  
                  error_message = urllib.parse.quote(str(e), safe="")
                  redirect_url = f"{frontend_url}/integrations/linear/redirect?error={error_message}&user_id={user_id}"
  
                  return RedirectResponse(url=redirect_url)
          else:
              # No code provided, redirect to frontend with error
              config = Config()
              frontend_url = config("FRONTEND_URL", default="http://localhost:3000")
  
              # Ensure frontend_url has protocol
              if frontend_url and not frontend_url.startswith(("http://", "https://")):
                  frontend_url = f"https://{frontend_url}"
  
              error_msg = "No authorization code received from Linear"
              if error:
                  error_msg = f"OAuth error: {error}"
              elif error_description:
                  error_msg = f"OAuth error: {error_description}"
  
              error_message = urllib.parse.quote(error_msg, safe="")
              redirect_url = f"{frontend_url}/integrations/linear/redirect?error={error_message}&user_id={user_id}"
  
              return RedirectResponse(url=redirect_url)
      except Exception as e:
          logger.exception("Linear OAuth callback failed")
  
          # Redirect to frontend with error
          config = Config()
          frontend_url = config("FRONTEND_URL", default="http://localhost:3000")
  
          # Ensure frontend_url has protocol
          if frontend_url and not frontend_url.startswith(("http://", "https://")):
              frontend_url = f"https://{frontend_url}"
  
          error_message = urllib.parse.quote(
              f"Linear OAuth callback failed: {str(e)}", safe=""
          )
          redirect_url = (
              f"{frontend_url}/integrations/linear/redirect?error={error_message}"
          )
  
          return RedirectResponse(url=redirect_url)
  
  
  @router.get("/linear/status/{user_id}")
  async def get_linear_status(
      user_id: str,
      linear_oauth: LinearOAuth = Depends(get_linear_oauth),
      user: dict = Depends(AuthService.check_auth),
  ) -> LinearIntegrationStatus:
      """Get Linear integration status for a user"""
      # Verify the authenticated user matches the requested user_id
      if user["user_id"] != user_id:
          raise HTTPException(
              status_code=403, detail="Cannot access other users' integration status"
          )
  
      user_info = linear_oauth.get_user_info(user_id)
  
      if not user_info:
          return LinearIntegrationStatus(user_id=user_id, is_connected=False)
  
      return LinearIntegrationStatus(
          user_id=user_id,
          is_connected=True,
          scope=user_info.get("scope"),
          expires_at=user_info.get("expires_at"),
      )
  
  
  @router.delete("/linear/revoke/{user_id}")
  async def revoke_linear_access(
      user_id: str,
      linear_oauth: LinearOAuth = Depends(get_linear_oauth),
      user: dict = Depends(AuthService.check_auth),
  ) -> Dict[str, Any]:
      """Revoke Linear OAuth access for a user"""
      # Verify the authenticated user matches the requested user_id
      if user["user_id"] != user_id:
          raise HTTPException(
              status_code=403, detail="Cannot revoke other users' integrations"
          )
  
      success = linear_oauth.revoke_access(user_id)
  
      if success:
          return {
              "status": "success",
              "message": "Linear access revoked successfully",
              "user_id": user_id,
          }
      else:
          raise HTTPException(status_code=500, detail="Failed to revoke Linear access")
  
  
  @router.post("/linear/save")
  async def save_linear_integration(
      request: LinearSaveRequest,
      integrations_service: IntegrationsService = Depends(get_integrations_service),
      user: dict = Depends(AuthService.check_auth),
  ) -> LinearSaveResponse:
      """Save Linear integration after OAuth callback"""
      try:
          # Get authenticated user_id
          user_id = user["user_id"]
          result = await integrations_service.save_linear_integration(request, user_id)
          return LinearSaveResponse(success=True, data=result, error=None)
      except Exception as e:
          logger.exception("Error saving Linear integration")
          return LinearSaveResponse(
              success=False,
              data=None,
              error=f"Failed to save Linear integration: {str(e)}",
          )
  
  
  @router.post("/jira/initiate")
  async def initiate_jira_oauth(
      request: OAuthInitiateRequest,
      jira_oauth: JiraOAuth = Depends(get_jira_oauth),
  ) -> Dict[str, Any]:
      """Initiate Jira OAuth flow."""
      try:
          logger.info(
              "Initiating Jira OAuth flow with redirect_uri=%s state=%s",
              request.redirect_uri,
              request.state,
          )
  
          signed_state = (
              _sign_oauth_state(request.state)
              if getattr(request, "state", None)
              else None
          )
          auth_url = jira_oauth.get_authorization_url(
              redirect_uri=request.redirect_uri, state=signed_state
          )
  
          return {
              "status": "success",
              "authorization_url": auth_url,
              "message": "Jira OAuth flow initiated successfully",
              "debug_info": {
                  "redirect_uri": request.redirect_uri,
                  "state": request.state,
                  "auth_url": auth_url,
              },
          }
      except Exception as exc:
          logger.exception("Jira OAuth initiation failed")
          raise HTTPException(
              status_code=500,
              detail=f"Failed to initiate Jira OAuth flow: {str(exc)}",
          )
  
  
  @router.get("/jira/callback")
  async def jira_oauth_callback(
      request: Request,
      jira_oauth: JiraOAuth = Depends(get_jira_oauth),
  ) -> Dict[str, Any]:
      """Handle Jira OAuth callback."""
      try:
          # Extract OAuth params
          code = request.query_params.get("code")
          state = request.query_params.get("state")
          error = request.query_params.get("error")
          error_description = request.query_params.get("error_description")
  
          # Verify signed state to get user_id
          user_id = _verify_oauth_state(state)
          if not user_id:
              raise HTTPException(
                  status_code=400, detail="Invalid or missing OAuth state"
              )
  
          # If we have an authorization code, exchange it for tokens and save to database
          if code:
              try:
                  # Create DB session and service
                  from app.core.database import SessionLocal
  
                  db = SessionLocal()
                  integrations_service = IntegrationsService(db)
  
                  from .integrations_schema import JiraSaveRequest
                  from datetime import datetime
  
                  # Prefer configured redirect URI so it exactly matches what's registered
                  config = Config()
                  redirect_uri = config("JIRA_REDIRECT_URI", default=None)
  
                  # If not configured, build a fallback using the incoming request's scheme/host/port
                  if not redirect_uri:
                      scheme = request.url.scheme or "http"
                      host = request.url.hostname or "localhost"
                      port = request.url.port
  
                      # Include port when it's non-standard for the scheme
                      if port and not (
                          (scheme == "http" and port == 80)
                          or (scheme == "https" and port == 443)
                      ):
                          host = f"{host}:{port}"
  
                      redirect_uri = (
                          f"{scheme}://{host}/api/v1/integrations/jira/callback"
                      )
  
                  logger.info(
                      f"Using Jira redirect_uri for token exchange: {redirect_uri}"
                  )
  
                  save_request = JiraSaveRequest(
                      code=code,
                      redirect_uri=redirect_uri,
                      instance_name="Jira Integration",
                      user_id=user_id,
                      integration_type="jira",
                      timestamp=datetime.utcnow().isoformat() + "Z",
                  )
  
                  # Save the integration (this will exchange the code and persist tokens)
                  save_result = await integrations_service.save_jira_integration(
                      save_request, user_id
                  )
  
                  db.close()
  
                  # Redirect to frontend with success info
                  config = Config()
                  frontend_url = config("FRONTEND_URL", default="http://localhost:3000")
  
                  # Ensure frontend_url has protocol
                  if frontend_url and not frontend_url.startswith(
                      ("http://", "https://")
                  ):
                      frontend_url = f"https://{frontend_url}"
  
                  redirect_url = f"{frontend_url}/integrations/jira/redirect?success=true&integration_id={save_result.get('integration_id')}&user_name={save_result.get('user_name', '')}"
  
                  return RedirectResponse(url=redirect_url)
  
              except Exception as e:
                  logger.exception("Failed to save Jira integration")
  
                  # Redirect to frontend with error
                  config = Config()
                  frontend_url = config("FRONTEND_URL", default="http://localhost:3000")
  
                  if frontend_url and not frontend_url.startswith(
                      ("http://", "https://")
                  ):
                      frontend_url = f"https://{frontend_url}"
  
                  error_message = urllib.parse.quote(str(e), safe="")
                  redirect_url = f"{frontend_url}/integrations/jira/redirect?error={error_message}&user_id={user_id}"
  
                  return RedirectResponse(url=redirect_url)
  
          else:
              # No code provided — redirect to frontend with error
              config = Config()
              frontend_url = config("FRONTEND_URL", default="http://localhost:3000")
  
              if frontend_url and not frontend_url.startswith(("http://", "https://")):
                  frontend_url = f"https://{frontend_url}"
  
              error_msg = "No authorization code received from Jira"
              if error:
                  error_msg = f"OAuth error: {error}"
              elif error_description:
                  error_msg = f"OAuth error: {error_description}"
  
              error_message = urllib.parse.quote(error_msg, safe="")
              redirect_url = f"{frontend_url}/integrations/jira/redirect?error={error_message}&user_id={user_id}"
  
              return RedirectResponse(url=redirect_url)
  
      except Exception as exc:
          logger.exception("Jira OAuth callback failed")
          raise HTTPException(
              status_code=400, detail=f"Jira OAuth callback failed: {str(exc)}"
          )
  
  
  @router.get("/jira/status/{user_id}")
  async def get_jira_status(
      user_id: str,
      integrations_service: IntegrationsService = Depends(get_integrations_service),
      user: dict = Depends(AuthService.check_auth),
  ) -> JiraIntegrationStatus:
      """Get Jira integration status for a user"""
      # Verify the authenticated user matches the requested user_id
      if user["user_id"] != user_id:
          raise HTTPException(
              status_code=403, detail="Cannot access other users' integration status"
          )
  
      return await integrations_service.get_jira_integration_status(user_id)
  
  
  @router.delete("/jira/revoke/{user_id}")
  async def revoke_jira_access(
      user_id: str,
      jira_oauth: JiraOAuth = Depends(get_jira_oauth),
      integrations_service: IntegrationsService = Depends(get_integrations_service),
      user: dict = Depends(AuthService.check_auth),
  ) -> Dict[str, Any]:
      """Revoke Jira OAuth access for a user"""
      # Verify the authenticated user matches the requested user_id
      if user["user_id"] != user_id:
          raise HTTPException(
              status_code=403, detail="Cannot revoke other users' integrations"
          )
  
      tokens_removed = jira_oauth.revoke_access(user_id)
      deactivated = await integrations_service.deactivate_jira_integrations_for_user(
          user_id
      )
  
      if tokens_removed or deactivated:
          return {
              "status": "success",
              "message": "Jira access revoked successfully",
              "user_id": user_id,
              "deactivated_integrations": deactivated,
          }
  
      raise HTTPException(status_code=500, detail="Failed to revoke Jira access")
  
  
  @router.get("/jira/{integration_id}/resources")
  async def get_jira_resources(
      integration_id: str,
      integrations_service: IntegrationsService = Depends(get_integrations_service),
      user: dict = Depends(AuthService.check_auth),
  ) -> Dict[str, Any]:
      """List Jira accessible resources for an integration."""
      try:
          # Verify the user owns this integration
          integration = await integrations_service.get_integration_by_id(integration_id)
          if not integration or integration.get("created_by") != user["user_id"]:
              raise HTTPException(
                  status_code=403, detail="Integration not found or access denied"
              )
  
          result = await integrations_service.get_jira_accessible_resources(
              integration_id
          )
          return {
              "status": "success",
              "integration_id": integration_id,
              "resources": result.get("resources", []),
              "site_id": result.get("site_id"),
              "site_url": result.get("site_url"),
          }
      except HTTPException:
          raise
      except Exception as exc:
          logger.exception("Error fetching Jira accessible resources")
          raise HTTPException(
              status_code=500,
              detail=f"Failed to fetch Jira accessible resources: {str(exc)}",
          )
  
  
  @router.get("/jira/{integration_id}/projects")
  async def get_jira_projects(
      integration_id: str,
      start_at: int = 0,
      max_results: int = 50,
      integrations_service: IntegrationsService = Depends(get_integrations_service),
      user: dict = Depends(AuthService.check_auth),
  ) -> Dict[str, Any]:
      """Fetch Jira projects for an integration."""
      try:
          # Verify the user owns this integration
          integration = await integrations_service.get_integration_by_id(integration_id)
          if not integration or integration.get("created_by") != user["user_id"]:
              raise HTTPException(
                  status_code=403, detail="Integration not found or access denied"
              )
  
          result = await integrations_service.get_jira_projects(
              integration_id, start_at=start_at, max_results=max_results
          )
          return {
              "status": "success",
              "integration_id": integration_id,
              "site_id": result.get("site_id"),
              "site_url": result.get("site_url"),
              "site_name": result.get("site_name"),
              "projects": result,
          }
      except HTTPException:
          raise
      except Exception as exc:
          logger.exception("Error fetching Jira projects")
          raise HTTPException(
              status_code=500,
              detail=f"Failed to fetch Jira projects: {str(exc)}",
          )
  
  
  @router.get("/jira/{integration_id}/projects/{project_key}")
  async def get_jira_project_details(
      integration_id: str,
      project_key: str,
  