content: from typing import Dict, Any, Optional
  from sqlalchemy.orm import Session
  from .sentry_oauth_v2 import SentryOAuthV2
  from .linear_oauth import LinearOAuth
  from .jira_oauth import JiraOAuth
  from .confluence_oauth import ConfluenceOAuth
  from .integrations_schema import (
      SentryIntegrationStatus,
      SentrySaveRequest,
      LinearIntegrationStatus,
      LinearSaveRequest,
      JiraSaveRequest,
      JiraIntegrationStatus,
      ConfluenceSaveRequest,
      ConfluenceIntegrationStatus,
      Integration as IntegrationSchema,
      IntegrationCreateRequest,
      IntegrationUpdateRequest,
      IntegrationResponse,
      IntegrationListResponse,
      IntegrationType,
      IntegrationStatus,
      AuthData,
      ScopeData,
      IntegrationMetadata,
      IntegrationSaveRequest,
  )
  from .integration_model import Integration
  from starlette.config import Config
  import time
  import uuid
  from app.modules.utils.logger import setup_logger
  from app.modules.integrations import hash_user_id
  from datetime import datetime, timedelta, timezone
  from .token_encryption import decrypt_token
  
  logger = setup_logger(__name__)
  
  
  class IntegrationsService:
      """Service layer for integrations"""
  
      def __init__(self, db: Session):
          self.db = db
          self.config = Config()
          self.sentry_oauth = SentryOAuthV2(self.config)
          self.linear_oauth = LinearOAuth(self.config)
          self.jira_oauth = JiraOAuth(self.config)
          self.confluence_oauth = ConfluenceOAuth(self.config)
  
      def _db_to_schema(self, db_integration: Integration) -> IntegrationSchema:
          """Convert database model to schema model"""
          # Convert to dict first to avoid linter issues with SQLAlchemy columns
          data = self._db_to_dict(db_integration)
  
          return IntegrationSchema(
              integration_id=data["integration_id"],
              name=data["name"],
              integration_type=IntegrationType(data["integration_type"]),
              status=IntegrationStatus(data["status"]),
              active=data["active"],
              auth_data=(
                  AuthData(**data["auth_data"])
                  if data["auth_data"]
                  else AuthData(
                      access_token=None,
                      refresh_token=None,
                      token_type="Bearer",
                      expires_at=None,
                      scope=None,
                      code=None,
                  )
              ),
              scope_data=(
                  ScopeData(**data["scope_data"])
                  if data["scope_data"]
                  else ScopeData(
                      org_slug=None,
                      installation_id=None,
                      workspace_id=None,
                      project_id=None,
                  )
              ),
              metadata=(
                  IntegrationMetadata(**data["metadata"])
                  if data["metadata"]
                  else IntegrationMetadata(
                      instance_name="", version=None, description=None
                  )
              ),
              unique_identifier=data["unique_identifier"],
              created_by=data["created_by"],
              created_at=(
                  datetime.fromisoformat(data["created_at"])
                  if data["created_at"]
                  else datetime.utcnow()
              ),
              updated_at=(
                  datetime.fromisoformat(data["updated_at"])
                  if data["updated_at"]
                  else datetime.utcnow()
              ),
          )
  
      def _db_to_dict(self, db_integration: Integration) -> Dict[str, Any]:
          """Convert database model to dictionary (for legacy methods)"""
          return {
              "integration_id": str(db_integration.integration_id),
              "name": str(db_integration.name),
              "integration_type": str(db_integration.integration_type),
              "status": str(db_integration.status),
              "active": bool(db_integration.active),
              "auth_data": db_integration.auth_data or {},
              "scope_data": db_integration.scope_data or {},
              "metadata": db_integration.integration_metadata or {},
              "unique_identifier": str(db_integration.unique_identifier),
              "created_by": str(db_integration.created_by),
              "created_at": (
                  db_integration.created_at.isoformat()
                  if hasattr(db_integration, "created_at")
                  and getattr(db_integration, "created_at", None)
                  else None
              ),
              "updated_at": (
                  db_integration.updated_at.isoformat()
                  if hasattr(db_integration, "updated_at")
                  and getattr(db_integration, "updated_at", None)
                  else None
              ),
          }
  
      async def get_sentry_integration_status(
          self, user_id: str
      ) -> SentryIntegrationStatus:
          """Get Sentry integration status for a user"""
          user_info = self.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"),
          )
  
      async def revoke_sentry_integration(self, user_id: str) -> bool:
          """Revoke Sentry integration for a user"""
          return self.sentry_oauth.revoke_access(user_id)
  
      def get_sentry_oauth_instance(self) -> SentryOAuthV2:
          """Get the Sentry OAuth integration instance"""
          return self.sentry_oauth
  
      async def validate_sentry_connection(self, user_id: str) -> bool:
          """Validate if a user has a valid Sentry connection"""
          return self.sentry_oauth.token_store.is_token_valid(user_id)
  
      async def get_sentry_token_info(self, user_id: str) -> Optional[Dict[str, Any]]:
          """Get Sentry token information for a user (for debugging)"""
          return self.sentry_oauth.token_store.get_tokens(user_id)
  
      async def refresh_sentry_token(self, integration_id: str) -> Dict[str, Any]:
          """Refresh expired Sentry access token"""
          try:
              from .token_encryption import decrypt_token, encrypt_token
              import httpx
  
              # Get the integration from database
              db_integration = (
                  self.db.query(Integration)
                  .filter(Integration.integration_id == integration_id)
                  .first()
              )
  
              if not db_integration:
                  raise Exception(f"Integration not found: {integration_id}")
  
              if getattr(db_integration, "integration_type") != "sentry":
                  raise Exception(
                      f"Integration {integration_id} is not a Sentry integration"
                  )
  
              # Get the auth data
              auth_data = getattr(db_integration, "auth_data")
              if not auth_data or not auth_data.get("refresh_token"):
                  raise Exception(
                      f"No refresh token found for integration {integration_id}"
                  )
  
              # Decrypt the refresh token
              refresh_token = decrypt_token(auth_data["refresh_token"])
  
              # Get OAuth client credentials from config
              client_id = self.config("SENTRY_CLIENT_ID", default="")
              client_secret = self.config("SENTRY_CLIENT_SECRET", default="")
  
              if not client_id or not client_secret:
                  raise Exception("Sentry OAuth credentials not configured")
  
              # Sentry OAuth token endpoint
              token_url = "https://sentry.io/oauth/token/"
  
              # Prepare refresh request
              refresh_data = {
                  "client_id": client_id,
                  "client_secret": client_secret,
                  "grant_type": "refresh_token",
                  "refresh_token": refresh_token,
              }
  
              # Make the refresh request
              async with httpx.AsyncClient(timeout=30.0) as client:
                  response = await client.post(token_url, data=refresh_data)
  
                  if response.status_code != 200:
                      # Safely parse response to extract structured error fields
                      sanitized_error = None
                      try:
                          error_data = response.json()
                          error_field = error_data.get("error", "")
                          error_description = error_data.get("error_description", "")
                          if error_field or error_description:
                              sanitized_error = f"error: {error_field}"
                              if error_description:
                                  sanitized_error += (
                                      f", error_description: {error_description[:200]}"
                                  )
                          else:
                              # JSON parsed but no error fields, use truncated response text
                              response_text = response.text or ""
                              sanitized_error = (
                                  response_text[:250]
                                  if response_text
                                  else "No response body"
                              )
                      except Exception:
                          # Fallback to truncated response.text if JSON parsing fails
                          response_text = response.text or ""
                          sanitized_error = (
                              response_text[:250] if response_text else "No response body"
                          )
  
                      # Log sanitized error at error level
                      logger.error(
                          f"Token refresh failed: {response.status_code} - {sanitized_error}"
                      )
                      # Log full response body at debug level for detailed troubleshooting
                      logger.debug(
                          f"Token refresh full response: status={response.status_code}, body={response.text}"
                      )
                      # Raise exception with minimal message
                      raise Exception(f"Token refresh failed: {response.status_code}")
  
                  token_response = response.json()
                  logger.info(
                      f"Token refresh successful, received: {list(token_response.keys())}"
                  )
  
                  # Parse token expiration
                  expires_at = datetime.utcnow() + timedelta(
                      seconds=token_response.get("expires_in", 3600)
                  )
  
                  # Update the integration with new tokens
                  new_auth_data = AuthData(
                      access_token=encrypt_token(token_response["access_token"]),
                      refresh_token=encrypt_token(
                          token_response.get("refresh_token", refresh_token)
                      ),
                      token_type=token_response.get("token_type", "bearer"),
                      expires_at=expires_at,
                      scope=token_response.get("scope", auth_data.get("scope", "")),
                      code=None,
                  )
  
                  # Update database
                  setattr(
                      db_integration, "auth_data", new_auth_data.model_dump(mode="json")
                  )
                  setattr(db_integration, "updated_at", datetime.utcnow())
  
                  self.db.commit()
                  self.db.refresh(db_integration)
  
                  logger.info(
                      f"Integration {integration_id} tokens refreshed successfully"
                  )
  
                  return {
                      "success": True,
                      "access_token": token_response["access_token"],
                      "expires_at": expires_at.isoformat(),
                      "scope": token_response.get("scope", ""),
                  }
  
          except Exception as e:
              logger.exception(
                  "Failed to refresh Sentry token", integration_id=integration_id
              )
              raise Exception(f"Token refresh failed: {str(e)}")
  
      async def get_valid_sentry_token(self, integration_id: str) -> str:
          """Get valid Sentry access token, refreshing if necessary"""
          try:
              from .token_encryption import decrypt_token
  
              # Get the integration from database
              db_integration = (
                  self.db.query(Integration)
                  .filter(Integration.integration_id == integration_id)
                  .first()
              )
  
              if not db_integration:
                  raise Exception(f"Integration not found: {integration_id}")
  
              # Get the auth data
              auth_data = getattr(db_integration, "auth_data")
              if not auth_data or not auth_data.get("access_token"):
                  raise Exception(
                      f"No access token found for integration {integration_id}"
                  )
  
              # Check if token is expired
              expires_at_str = auth_data.get("expires_at")
              if expires_at_str:
                  try:
                      expires_at = datetime.fromisoformat(
                          expires_at_str.replace("Z", "+00:00")
                      )
                      if datetime.utcnow() >= expires_at:
                          # Token expired, refresh it
                          logger.info(
                              f"Token expired for integration {integration_id}, refreshing..."
                          )
                          refresh_result = await self.refresh_sentry_token(integration_id)
                          return refresh_result["access_token"]
                  except ValueError:
                      logger.warning(
                          f"Invalid expiration date format for integration {integration_id}"
                      )
  
              # Token is still valid, decrypt and return it
              return decrypt_token(auth_data["access_token"])
  
          except Exception as e:
              logger.exception(
                  "Failed to get valid Sentry token", integration_id=integration_id
              )
              raise Exception(f"Failed to get valid token: {str(e)}")
  
      async def _exchange_code_for_tokens(
          self, code: str, redirect_uri: str
      ) -> Dict[str, Any]:
          """Exchange OAuth authorization code for access tokens and get organization info"""
          try:
              import httpx
  
              # Get OAuth client credentials from config
              client_id = self.config("SENTRY_CLIENT_ID", default="")
              client_secret = self.config("SENTRY_CLIENT_SECRET", default="")
              # Use the redirect_uri from the request instead of hardcoded config
  
              # Debug logging for OAuth token exchange (DEBUG level only)
              logger.debug(
                  "OAuth token exchange starting",
                  code_length=len(code),
                  has_client_id=bool(client_id),
                  has_client_secret=bool(client_secret),
                  has_redirect_uri=bool(redirect_uri),
              )
  
              if not client_id or not client_secret or not redirect_uri:
                  missing = []
                  if not client_id:
                      missing.append("SENTRY_CLIENT_ID")
                  if not client_secret:
                      missing.append("SENTRY_CLIENT_SECRET")
                  if not redirect_uri:
                      missing.append("SENTRY_REDIRECT_URI")
                  raise Exception(
                      f"Sentry OAuth credentials not configured. Missing: {', '.join(missing)}"
                  )
  
              # Sentry OAuth token endpoint
              token_url = "https://sentry.io/oauth/token/"
  
              # Prepare token data for OAuth flow
              # Note: Including redirect_uri as it may be required for validation
              token_data = {
                  "client_id": client_id,
                  "client_secret": client_secret,
                  "grant_type": "authorization_code",
                  "code": code,
                  "redirect_uri": redirect_uri,
              }
  
              logger.debug(
                  "Token exchange request prepared",
                  token_url=token_url,
                  fields=list(token_data.keys()),
              )
  
              # Make the token exchange request
              async with httpx.AsyncClient(timeout=30.0) as client:
                  logger.debug("Making OAuth token exchange request")
  
                  # Use form-encoded data as required by OAuth 2.0 spec
                  response = await client.post(
                      token_url,
                      data=token_data,
                      headers={"Content-Type": "application/x-www-form-urlencoded"},
                  )
  
                  # Log response details
                  logger.debug(
                      "OAuth token exchange response",
                      status_code=response.status_code,
                      content_length=len(response.content),
                  )
  
                  if response.status_code != 200:
                      # Try to parse error response for more details
                      try:
                          error_data = response.json()
                          error_type = error_data.get("error", "unknown")
                          error_description = error_data.get(
                              "error_description", "No description provided"
                          )
  
                          logger.error(
                              "OAuth token exchange failed",
                              status_code=response.status_code,
                              error_type=error_type,
                              error_description=error_description,
                          )
  
                          # Log helpful hints for common errors at DEBUG level
                          if error_type == "invalid_grant":
                              logger.debug(
                                  "Invalid grant error - common causes: "
                                  "expired code, code already used, redirect URI mismatch, "
                                  "or incorrect client credentials"
                              )
  
                      except Exception:
                          logger.error(
                              "OAuth token exchange failed",
                              status_code=response.status_code,
                              response_text=response.text[:200],
                          )  # Truncate response
  
                  response.raise_for_status()
  
                  # Parse the response
                  token_response = response.json()
                  logger.info("OAuth token exchange successful")
  
                  # Get organization information using the access token
                  org_info = await self._get_sentry_organization_info(
                      token_response["access_token"]
                  )
  
                  # Extract token information with organization data
                  tokens = {
                      "access_token": token_response.get("access_token"),
                      "refresh_token": token_response.get("refresh_token"),
                      "token_type": token_response.get("token_type", "bearer"),
                      "expires_in": token_response.get("expires_in"),
                      "expires_at": token_response.get("expires_at"),
                      "scope": token_response.get("scope"),
                      "user": token_response.get("user"),
                      "organization": org_info,
                  }
  
                  logger.debug(
                      "Token exchange complete",
                      token_type=tokens.get("token_type"),
                      has_refresh_token=bool(tokens.get("refresh_token")),
                  )
                  return tokens
  
          except Exception as e:
              logger.exception("Failed to exchange OAuth code for tokens")
              raise Exception(f"OAuth token exchange failed: {str(e)}")
  
      async def _get_sentry_organization_info(
          self, access_token: str
      ) -> Optional[Dict[str, Any]]:
          """Get organization information from Sentry API"""
          try:
              import httpx
  
              headers = {
                  "Authorization": f"Bearer {access_token}",
                  "Content-Type": "application/json",
              }
  
              # Get organizations for the user
              async with httpx.AsyncClient(timeout=30.0) as client:
                  response = await client.get(
                      "https://sentry.io/api/0/organizations/", headers=headers
                  )
  
                  if response.status_code != 200:
                      logger.error(
                          f"Failed to get organization info: {response.status_code}"
                      )
                      return None
  
                  organizations = response.json()
                  # Return the first organization (Sentry OAuth is typically scoped to one organization)
                  if organizations:
                      org = organizations[0]
                      logger.debug(
                          "Retrieved organization info", org_slug=org.get("slug")
                      )
                      return {
                          "id": str(org.get("id")),
                          "slug": org.get("slug"),
                          "name": org.get("name"),
                      }
  
                  return None
  
          except Exception:
              logger.exception("Error getting organization info")
              return None
  
      async def make_sentry_api_call(
          self,
          integration_id: str,
          endpoint: str,
          method: str = "GET",
          data: Optional[Dict[str, Any]] = None,
      ) -> Optional[Dict[str, Any]]:
          """Make an API call to Sentry using stored integration tokens"""
          try:
              # Get valid access token (will refresh if expired)
              access_token = await self.get_valid_sentry_token(integration_id)
  
              # Make the API call to Sentry
              import httpx
  
              headers = {
                  "Authorization": f"Bearer {access_token}",
                  "Content-Type": "application/json",
              }
  
              url = f"https://sentry.io/api/0{endpoint}"
  
              async with httpx.AsyncClient() as client:
                  if method.upper() == "GET":
                      response = await client.get(url, headers=headers)
                  elif method.upper() == "POST":
                      response = await client.post(url, headers=headers, json=data)
                  elif method.upper() == "PUT":
                      response = await client.put(url, headers=headers, json=data)
                  elif method.upper() == "DELETE":
                      response = await client.delete(url, headers=headers)
                  else:
                      raise Exception(f"Unsupported HTTP method: {method}")
  
                  response.raise_for_status()
                  return response.json()
  
          except Exception as e:
              logger.exception("Error making Sentry API call")
              raise Exception(f"Failed to make Sentry API call: {str(e)}")
  
      async def get_sentry_organizations(
          self, integration_id: str
      ) -> Optional[Dict[str, Any]]:
          """Get Sentry organizations for an integration"""
          return await self.make_sentry_api_call(integration_id, "/organizations/")
  
      async def get_sentry_projects(
          self, integration_id: str, org_slug: str
      ) -> Optional[Dict[str, Any]]:
          """Get Sentry projects for an organization"""
          return await self.make_sentry_api_call(
              integration_id, f"/organizations/{org_slug}/projects/"
          )
  
      async def get_sentry_issues(
          self, integration_id: str, org_slug: str, project_slug: str
      ) -> Optional[Dict[str, Any]]:
          """Get Sentry issues for a project"""
          return await self.make_sentry_api_call(
              integration_id, f"/projects/{org_slug}/{project_slug}/issues/"
          )
  
      async def save_sentry_integration(
          self, request: SentrySaveRequest, user_id: str
      ) -> Dict[str, Any]:
          """Save Sentry integration with authorization code (backend handles token exchange)"""
          try:
              from .token_encryption import encrypt_token
  
              logger.info(
                  "Processing Sentry integration",
                  instance_name=request.instance_name,
                  integration_type=request.integration_type,
              )
              logger.debug(
                  "OAuth code validation",
                  code_length=len(request.code),
                  has_redirect_uri=bool(request.redirect_uri),
              )
  
              # Validate the authorization code format and timing
              if not request.code or len(request.code) < 20:
                  raise Exception("Invalid authorization code format")
  
              # Validate redirect URI
              if not request.redirect_uri:
                  raise Exception("Redirect URI is required for OAuth token exchange")
  
              # Check if the code might be expired (OAuth codes typically expire in 10 minutes)
              try:
                  request_time = datetime.fromisoformat(
                      request.timestamp.replace("Z", "+00:00")
                  )
                  # Use timezone-aware current time to match the request time
                  from datetime import timezone
  
                  current_time = datetime.now(timezone.utc)
                  time_diff = (current_time - request_time).total_seconds()
  
                  if time_diff > 600:  # 10 minutes
                      logger.warning(
                          "Authorization code might be expired", age_seconds=time_diff
                      )
                      raise Exception(
                          f"Authorization code may be expired (age: {time_diff} seconds)"
                      )
  
              except ValueError as e:
                  logger.warning(f"Could not parse request timestamp: {e}")
  
              # Exchange authorization code for tokens
              logger.debug("Exchanging authorization code for tokens")
              tokens = await self.sentry_oauth.exchange_code_for_tokens(
                  request.code, request.redirect_uri
              )
  
              if not tokens.get("access_token"):
                  raise Exception("Failed to obtain access token from OAuth exchange")
  
              if not tokens.get("organization"):
                  raise Exception("Failed to retrieve organization information")
  
              # Generate a unique integration ID
              integration_id = str(uuid.uuid4())
  
              # Parse the timestamp
              try:
                  created_at = datetime.fromisoformat(
                      request.timestamp.replace("Z", "+00:00")
                  )
              except ValueError:
                  created_at = datetime.utcnow()
  
              # Parse token expiration
              try:
                  expires_at = datetime.fromisoformat(
                      tokens["expires_at"].replace("Z", "+00:00")
                  )
              except (ValueError, KeyError):
                  expires_at = datetime.utcnow() + timedelta(
                      seconds=tokens.get("expires_in", 3600)
                  )
  
              # Create auth data with encrypted tokens
              auth_data = AuthData(
                  access_token=encrypt_token(
                      tokens["access_token"]
                  ),  # Encrypt for security
                  refresh_token=encrypt_token(
                      tokens["refresh_token"]
                  ),  # Encrypt for security
                  token_type=tokens.get("token_type", "bearer"),
                  expires_at=expires_at,
                  scope=tokens.get("scope", ""),
                  code=None,  # Don't store the code after exchange
              )
  
              # Create scope data from organization information
              org_info = tokens["organization"]
  
              # Check if this Potpie user already integrated this Sentry org
              existing_integration = await self.check_existing_sentry_integration(
                  org_info["slug"], user_id
              )
              if existing_integration:
                  logger.warning(
                      f"Sentry account (org: {org_info['slug']}, user: {hash_user_id(user_id)}) is already integrated: {existing_integration['integration_id']}"
                  )
                  raise Exception(
                      f"Sentry account is already integrated. "
                      f"Existing integration ID: {existing_integration['integration_id']}. "
                      f"Please delete the existing integration first if you want to reconnect."
                  )
  
              scope_data = ScopeData(
                  org_slug=org_info["slug"],
                  installation_id=None,  # Not needed for OAuth flow
                  workspace_id=None,
                  project_id=None,
              )
  
              # Create metadata with user and organization info
              metadata = IntegrationMetadata(
                  instance_name=request.instance_name,
                  created_via="oauth",
                  description=f"Sentry integration for {org_info['name']}",
                  version=None,
              )
  
              # Create database model
              db_integration = Integration()
              setattr(db_integration, "integration_id", integration_id)
              setattr(db_integration, "name", request.instance_name)
              setattr(db_integration, "integration_type", IntegrationType.SENTRY.value)
              setattr(db_integration, "status", IntegrationStatus.ACTIVE.value)
              setattr(db_integration, "active", True)
              setattr(db_integration, "auth_data", auth_data.model_dump(mode="json"))
              setattr(db_integration, "scope_data", scope_data.model_dump(mode="json"))
              setattr(
                  db_integration, "integration_metadata", metadata.model_dump(mode="json")
              )
              setattr(
                  db_integration,
                  "unique_identifier",
                  f"{org_info['slug']}-{user_id}",  # Use Potpie user_id for uniqueness
              )
              setattr(
                  db_integration, "created_by", user_id
              )  # Use Potpie user_id, not Sentry OAuth user ID
              setattr(db_integration, "created_at", created_at)
              setattr(db_integration, "updated_at", created_at)
  
              # Save to database
              self.db.add(db_integration)
              self.db.commit()
              self.db.refresh(db_integration)
              logger.info(
                  f"Integration saved to database with encrypted tokens: {integration_id}"
              )
  
              # Return the integration data
              return {
                  "integration_id": integration_id,
                  "instance_name": request.instance_name,
                  "status": "active",
                  "integration_type": request.integration_type,
                  "org_slug": org_info["slug"],
                  "org_name": org_info["name"],
                  "user_email": tokens.get("user", {}).get("email", "unknown"),
                  "created_at": created_at.isoformat(),
                  "has_tokens": True,
                  "requires_oauth": False,
              }
  
          except Exception as e:
              logger.exception("Error saving Sentry integration")
  
              # Provide more helpful error messages based on the error type
              error_message = str(e)
              if "invalid_grant" in error_message:
                  error_message = (
                      "OAuth authorization failed. This usually means:\n"
                      "1. The authorization code has expired (codes expire in ~10 minutes)\n"
                      "2. The authorization code has already been used\n"
                      "3. The redirect URI doesn't match what was used during authorization\n"
                      "4. The client credentials are incorrect\n\n"
                      "Please try the OAuth flow again with a fresh authorization code."
                  )
              elif "expired" in error_message.lower():
                  error_message = (
                      "The authorization code has expired. OAuth codes typically expire in 10 minutes. "
                      "Please initiate a new OAuth flow to get a fresh authorization code."
                  )
  
              raise Exception(f"Failed to save Sentry integration: {error_message}")
  
      async def get_integration_by_id(
          self, integration_id: str
      ) -> Optional[Dict[str, Any]]:
          """Get integration by ID from database (legacy method)"""
          db_integration = (
              self.db.query(Integration)
              .filter(Integration.integration_id == integration_id)
              .first()
          )
          if db_integration:
              return self._db_to_dict(db_integration)
          return None
  
  