/**
 * Middleware для интеграции системы безопасности в существующие резолверы
 * 
 * Автоматически применяет фильтрацию данных и аудит к резолверам поставок
 * без необходимости переписывания всего кода
 */

import { OrganizationType } from '@prisma/client'
import { GraphQLError } from 'graphql'

import { FEATURE_FLAGS } from '../../config/features'
import { SecurityLogger } from '../../lib/security-logger'

import { CommercialDataAudit } from './commercial-data-audit'
import { ParticipantIsolation } from './participant-isolation'
import { SupplyDataFilter } from './supply-data-filter'
import type { SecurityContext, ResourceType, CommercialAccessType } from './types'

import { createSecurityContext } from './index'


/**
 * Конфигурация безопасности для резолвера
 */
interface SecurityConfig {
  resourceType: ResourceType
  auditAction: CommercialAccessType
  requiredRole?: OrganizationType[]
  enableFiltering: boolean
  enableAudit: boolean
  enablePartnershipCheck: boolean
}

/**
 * Маппинг резолверов на конфигурации безопасности
 */
const RESOLVER_SECURITY_CONFIG: Record<string, SecurityConfig> = {
  // Query резолверы
  'Query.supplyOrders': {
    resourceType: 'SUPPLY_ORDER',
    auditAction: 'VIEW_PRICE',
    enableFiltering: true,
    enableAudit: true,
    enablePartnershipCheck: false,
  },
  'Query.mySupplyOrders': {
    resourceType: 'SUPPLY_ORDER',
    auditAction: 'VIEW_PRICE',
    enableFiltering: true,
    enableAudit: true,
    enablePartnershipCheck: false,
  },
  'Query.pendingSuppliesCount': {
    resourceType: 'SUPPLY_ORDER',
    auditAction: 'VIEW_PRICE',
    enableFiltering: false,
    enableAudit: true,
    enablePartnershipCheck: false,
  },

  // Mutation резолверы
  'Mutation.createSupplyOrder': {
    resourceType: 'SUPPLY_ORDER',
    auditAction: 'VIEW_RECIPE',
    requiredRole: ['SELLER', 'FULFILLMENT'],
    enableFiltering: false,
    enableAudit: true,
    enablePartnershipCheck: true,
  },
  'Mutation.updateSupplyOrderStatus': {
    resourceType: 'SUPPLY_ORDER',
    auditAction: 'VIEW_PRICE',
    enableFiltering: true,
    enableAudit: true,
    enablePartnershipCheck: false,
  },
  'Mutation.supplierApproveOrder': {
    resourceType: 'SUPPLY_ORDER',
    auditAction: 'VIEW_PRICE',
    requiredRole: ['WHOLESALE'],
    enableFiltering: true,
    enableAudit: true,
    enablePartnershipCheck: true,
  },
  'Mutation.supplierRejectOrder': {
    resourceType: 'SUPPLY_ORDER',
    auditAction: 'VIEW_PRICE',
    requiredRole: ['WHOLESALE'],
    enableFiltering: true,
    enableAudit: true,
    enablePartnershipCheck: true,
  },
  'Mutation.assignLogisticsToSupply': {
    resourceType: 'SUPPLY_ORDER',
    auditAction: 'VIEW_CONTACTS',
    requiredRole: ['SELLER', 'FULFILLMENT'],
    enableFiltering: true,
    enableAudit: true,
    enablePartnershipCheck: true,
  },
}

/**
 * Middleware функция для применения безопасности к резолверу
 */
export function applySecurityMiddleware(
  resolverName: string,
  originalResolver: Function,
): Function {
  const config = RESOLVER_SECURITY_CONFIG[resolverName]
  
  // Если конфигурация не найдена - возвращаем оригинальный резолвер
  if (!config) {
    return originalResolver
  }

  return async function securedResolver(parent: unknown, args: unknown, context: unknown, info: unknown) {
    // Проверяем включена ли система безопасности
    if (!FEATURE_FLAGS.SUPPLY_DATA_SECURITY.enabled) {
      return originalResolver(parent, args, context, info)
    }

    const securityContext = createSecurityContext(context as Record<string, unknown>)
    
    try {
      // 1. Проверка аутентификации
      if (!securityContext.user.id) {
        throw new GraphQLError('Authentication required', {
          extensions: { code: 'UNAUTHENTICATED' },
        })
      }

      // 2. Проверка роли если требуется
      if (config.requiredRole && !config.requiredRole.includes(securityContext.user.organizationType)) {
        
        // Логируем попытку несанкционированного доступа
        if (config.enableAudit && FEATURE_FLAGS.SUPPLY_DATA_SECURITY.auditEnabled) {
          await CommercialDataAudit.logUnauthorizedAccess((context as any).prisma, {
            userId: securityContext.user.id,
            organizationType: securityContext.user.organizationType,
            resourceType: config.resourceType,
            resourceId: 'unknown',
            reason: `Insufficient role: ${securityContext.user.organizationType}, required: ${config.requiredRole.join(', ')}`,
            ipAddress: securityContext.ipAddress,
            userAgent: securityContext.userAgent,
          })
        }
        
        throw new GraphQLError('Insufficient permissions', {
          extensions: { code: 'FORBIDDEN' },
        })
      }

      // 3. Проверка партнерских отношений если требуется
      if (config.enablePartnershipCheck && (args as any)?.input?.partnerId) {
        try {
          await ParticipantIsolation.validatePartnerAccess(
            (context as any).prisma,
            securityContext.user.organizationId,
            (args as any).input.partnerId,
            securityContext,
          )
        } catch (error) {
          SecurityLogger.logSecurityError(error as Error, {
            operation: 'partnershipCheck',
            resolverName,
            userId: securityContext.user.id,
            organizationType: securityContext.user.organizationType,
          })
          throw error
        }
      }

      // 4. Логирование доступа
      if (config.enableAudit && FEATURE_FLAGS.SUPPLY_DATA_SECURITY.auditEnabled) {
        await CommercialDataAudit.logAccess((context as any).prisma, {
          userId: securityContext.user.id,
          organizationType: securityContext.user.organizationType,
          action: config.auditAction,
          resourceType: config.resourceType,
          metadata: { resolverName, args },
          ipAddress: securityContext.ipAddress,
          userAgent: securityContext.userAgent,
        })
      }

      // 5. Выполнение оригинального резолвера
      let result = await originalResolver(parent, args, context, info)

      // 6. Фильтрация результата если включена
      if (config.enableFiltering && result && config.resourceType === 'SUPPLY_ORDER') {
        result = await filterSupplyOrderResult(result, securityContext)
      }

      return result

    } catch (error) {
      SecurityLogger.logSecurityError(error as Error, {
        operation: 'securityMiddleware',
        resolverName,
        resourceType: config.resourceType,
        userId: securityContext.user.id,
        organizationType: securityContext.user.organizationType,
      })
      throw error
    }
  }
}

/**
 * Фильтрует результат с заказами поставок
 */
async function filterSupplyOrderResult(
  result: unknown,
  context: SecurityContext,
): Promise<unknown> {
  // Если это массив заказов
  if (Array.isArray(result)) {
    return Promise.all(
      result.map(async (order) => {
        if (order && typeof order === 'object' && 'id' in order) {
          const filtered = SupplyDataFilter.filterSupplyOrder(order as any, context)
          return filtered.data
        }
        return order
      }),
    )
  }

  // Если это одиночный заказ
  if (result && typeof result === 'object' && 'id' in result) {
    const filtered = SupplyDataFilter.filterSupplyOrder(result as any, context)
    return filtered.data
  }

  // Если это ответ с заказом внутри
  if (result && typeof result === 'object' && 'order' in result) {
    const resultObj = result as any
    if (resultObj.order && typeof resultObj.order === 'object' && 'id' in resultObj.order) {
      const filtered = SupplyDataFilter.filterSupplyOrder(resultObj.order, context)
      return {
        ...resultObj,
        order: filtered.data,
      }
    }
  }

  return result
}

/**
 * Автоматически применяет middleware ко всем резолверам из конфигурации
 */
export function wrapResolversWithSecurity(resolvers: Record<string, any>): Record<string, any> {
  const wrappedResolvers = { ...resolvers }

  // Обрабатываем Query резолверы
  if (wrappedResolvers.Query) {
    for (const [queryName, resolver] of Object.entries(wrappedResolvers.Query)) {
      const resolverName = `Query.${queryName}`
      if (RESOLVER_SECURITY_CONFIG[resolverName] && typeof resolver === 'function') {
        wrappedResolvers.Query[queryName] = applySecurityMiddleware(resolverName, resolver)
        
        SecurityLogger.logFilteringPerformance({
          operation: 'wrapResolver',
          duration: 0,
          recordsFiltered: 0,
          fieldsRemoved: 0,
          cacheHit: false,
        })
      }
    }
  }

  // Обрабатываем Mutation резолверы
  if (wrappedResolvers.Mutation) {
    for (const [mutationName, resolver] of Object.entries(wrappedResolvers.Mutation)) {
      const resolverName = `Mutation.${mutationName}`
      if (RESOLVER_SECURITY_CONFIG[resolverName] && typeof resolver === 'function') {
        wrappedResolvers.Mutation[mutationName] = applySecurityMiddleware(resolverName, resolver)
      }
    }
  }

  return wrappedResolvers
}

/**
 * Добавляет новую конфигурацию безопасности для резолвера
 */
export function addSecurityConfig(resolverName: string, config: SecurityConfig): void {
  RESOLVER_SECURITY_CONFIG[resolverName] = config
}

/**
 * Получает конфигурацию безопасности для резолвера
 */
export function getSecurityConfig(resolverName: string): SecurityConfig | undefined {
  return RESOLVER_SECURITY_CONFIG[resolverName]
}

/**
 * Выводит список всех защищенных резолверов
 */
export function listSecuredResolvers(): string[] {
  return Object.keys(RESOLVER_SECURITY_CONFIG)
}