/**
 * Create an integration with encryption and health checks
 *
 * Supports both REST API and SQL integrations.
 * For SQL integrations, pass sqlConnectionConfig with the database connection details.
 */

import { api, internal } from '../_generated/api';
import { Id } from '../_generated/dataModel';
import type { ActionCtx } from '../_generated/server';
import type {
  AuditLogActorType,
  AuditLogCategory,
  AuditLogStatus,
} from '../audit_logs/types';
import { createDebugLog } from '../lib/debug_log';
import { encryptCredentials } from './encrypt_credentials';
import { runHealthCheck } from './run_health_check';
import {
  AuthMethod,
  ApiKeyAuth,
  BasicAuth,
  OAuth2Auth,
  ConnectionConfig,
  Capabilities,
  ConnectorConfig,
  SqlConnectionConfig,
  SqlOperation,
} from './types';

const debugLog = createDebugLog('DEBUG_INTEGRATIONS', '[Integrations]');

export interface CreateIntegrationArgs {
  organizationId: string;
  name: string;
  title: string;
  description?: string;
  authMethod: AuthMethod;
  supportedAuthMethods?: AuthMethod[];
  apiKeyAuth?: ApiKeyAuth;
  basicAuth?: BasicAuth;
  oauth2Auth?: OAuth2Auth;
  connectionConfig?: ConnectionConfig;
  capabilities?: Capabilities;
  connector?: ConnectorConfig;
  // SQL integration fields
  type?: 'rest_api' | 'sql';
  sqlConnectionConfig?: SqlConnectionConfig;
  sqlOperations?: SqlOperation[];
  // OAuth2 provider config (from config.json)
  oauth2Config?: {
    authorizationUrl: string;
    tokenUrl: string;
    scopes?: string[];
  };
  iconStorageId?: Id<'_storage'>;
  metadata?: unknown;
}

/**
 * Create an integration, encrypt credentials, and run initial health check
 */
export async function createIntegration(
  ctx: ActionCtx,
  args: CreateIntegrationArgs,
): Promise<Id<'integrations'>> {
  // Verify access (RLS check)
  await ctx.runQuery(api.integrations.queries.list, {
    organizationId: args.organizationId,
  });

  // Validate SQL connection config for SQL integrations
  if (args.type === 'sql') {
    if (!args.sqlConnectionConfig) {
      throw new Error('SQL integration requires sqlConnectionConfig');
    }
    if (!args.sqlConnectionConfig.engine) {
      throw new Error(
        'SQL integration requires an engine type (mssql, postgres, or mysql)',
      );
    }
  }

  // Encrypt credentials
  const { apiKeyAuth, basicAuth, oauth2Auth } = await encryptCredentials(args);

  const hasCredentials =
    !!args.apiKeyAuth || !!args.basicAuth || !!args.oauth2Auth;

  // Run health check (skip for integrations without credentials)
  if (hasCredentials) {
    await runHealthCheck(ctx, args);
  }

  // Create integration - type assertion needed due to schema mismatches between shared types and mutation
  // The generated API types need regeneration (run `bunx convex dev`)
  // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Convex runMutation return type mismatch with generated API
  const integrationId = (await ctx.runMutation(
    internal.integrations.internal_mutations.createIntegration,
    {
      organizationId: args.organizationId,
      name: args.name,
      title: args.title,
      description: args.description,
      status: hasCredentials ? 'active' : 'inactive',
      isActive: hasCredentials,
      authMethod:
        args.authMethod === 'bearer_token' ? 'api_key' : args.authMethod,
      supportedAuthMethods: args.supportedAuthMethods,
      apiKeyAuth,
      basicAuth: basicAuth
        ? {
            username: basicAuth.username ?? '',
            passwordEncrypted: basicAuth.passwordEncrypted,
          }
        : undefined,
      oauth2Auth,
      // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- connectionConfig is v.any() in schema
      connectionConfig: args.connectionConfig as
        | Record<string, unknown>
        | undefined,
      capabilities: args.capabilities,
      connector: args.connector,
      // SQL integration fields
      type: args.type,
      sqlConnectionConfig: args.sqlConnectionConfig,
      sqlOperations: args.sqlOperations,
      oauth2Config: args.oauth2Config,
      iconStorageId: args.iconStorageId,
      metadata: args.metadata,
    },
  )) as Id<'integrations'>;

  debugLog(
    `Integration Create Successfully created ${args.name} integration with ID: ${integrationId}`,
  );

  try {
    await ctx.runMutation(
      internal.audit_logs.internal_mutations.createAuditLog,
      {
        organizationId: args.organizationId,
        actorId: 'system',
        actorType: 'system' as AuditLogActorType,
        action: 'create_integration',
        category: 'integration' as AuditLogCategory,
        resourceType: 'integration',
        resourceId: String(integrationId),
        resourceName: args.name,
        newState: {
          name: args.name,
          title: args.title,
          type: args.type ?? 'rest_api',
          authMethod: args.authMethod,
        },
        status: 'success' as AuditLogStatus,
      },
    );
  } catch (error) {
    debugLog(
      `Failed to create audit log for integration ${integrationId}:`,
      error,
    );
  }

  return integrationId;
}
