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

import { GraphQLError } from 'graphql'

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

import { SecurityContext, FilteredData, DataAccessLevel } from './types'

/**
 * Интерфейс заказа поставки для фильтрации
 */
interface SupplyOrder {
  id: string
  status: string
  organizationId: string
  fulfillmentCenterId?: string
  logisticsPartnerId?: string
  deliveryDate?: Date
  totalItems: number

  // Коммерческие данные
  productPrice?: number | null
  fulfillmentServicePrice?: number | null
  logisticsPrice?: number | null
  totalAmount?: number | null

  // Производственные данные
  items: Array<{
    id: string
    productId: string // Обязательное поле GraphQL
    product: {
      id: string
      name: string
      article: string // Обязательное поле GraphQL
      price: number // Обязательное поле GraphQL
      quantity: number // Обязательное поле GraphQL
      images: string[] // Обязательное поле GraphQL
      isActive: boolean // Обязательное поле GraphQL
      createdAt: string // Обязательное поле GraphQL
      updatedAt: string // Обязательное поле GraphQL
      organization: { // Обязательное поле GraphQL
        id: string
        inn: string
        name: string
        type: string
      }
      organizationId: string
    }
    quantity: number
    price?: number | null
    totalPrice: number // Обязательное поле GraphQL
    recipe?: {
      services: Array<{ id: string; name: string; price?: number }>
      fulfillmentConsumables: Array<{
        id: string
        name: string
        quantity: number
        pricePerUnit?: number
        price?: number
      }>
      sellerConsumables: Array<{
        id: string
        name: string
        quantity: number
        pricePerUnit?: number
        price?: number
      }>
    }
  }>

  // Логистические данные
  routes?: Array<{
    from: string
    fromAddress: string
    to: string
    toAddress: string
    packagesCount?: number
    volume?: number
  }>

  // Параметры поставки (опциональные)
  packagesCount?: number | null
  volume?: number | null
  readyDate?: Date | null
  notes?: string | null
}

/**
 * Отфильтрованный заказ поставки
 * Сохраняем обязательные поля из GraphQL схемы
 */
interface FilteredSupplyOrder extends Partial<SupplyOrder> {
  id: string // Обязательное поле
  organizationId: string // Обязательное поле
  partnerId: string // Обязательное поле
  partner: any // Обязательное поле - объект Organization
  organization: any // Обязательное поле - объект Organization
  deliveryDate: string | Date // Обязательное поле
  status: string // Обязательное поле  
  totalAmount: number // Обязательное поле
  totalItems: number // Обязательное поле
  createdAt: string | Date // Обязательное поле
  updatedAt: string | Date // Обязательное поле
  routes: any[] // Обязательное поле (массив маршрутов)
  items: any[] // Обязательное поле (массив товаров)
}

export class SupplyDataFilter {
  /**
   * Главный метод фильтрации заказа поставки по роли пользователя
   */
  static filterSupplyOrder(order: SupplyOrder, context: SecurityContext): FilteredData<FilteredSupplyOrder> {
    const startTime = Date.now()

    try {
      if (!context.user) {
        throw new GraphQLError('User context required for supply order filtering')
      }
      const { organizationType, organizationId } = context.user

      let filteredOrder: FilteredSupplyOrder
      let removedFields: string[] = []
      let accessLevel: DataAccessLevel = 'NONE'

      switch (organizationType) {
        case 'SELLER':
          ;({ data: filteredOrder, removedFields, accessLevel } = this.filterForSeller(order, organizationId))
          break

        case 'WHOLESALE':
          ;({ data: filteredOrder, removedFields, accessLevel } = this.filterForWholesale(order, organizationId))
          break

        case 'FULFILLMENT':
          ;({ data: filteredOrder, removedFields, accessLevel } = this.filterForFulfillment(order, organizationId))
          break

        case 'LOGIST':
          ;({ data: filteredOrder, removedFields, accessLevel } = this.filterForLogist(order, organizationId))
          break

        default:
          throw new GraphQLError('Unauthorized organization type', {
            extensions: { code: 'FORBIDDEN' },
          })
      }

      const filtered = removedFields.length > 0

      // Логирование доступа
      if (FEATURE_FLAGS.SUPPLY_DATA_SECURITY.auditEnabled) {
        SecurityLogger.logDataAccess({
          userId: context.user.id,
          organizationType: context.user.organizationType,
          action: 'VIEW_PRICE', // или другой тип в зависимости от removedFields
          resource: 'SUPPLY_ORDER',
          resourceId: order.id,
          filtered,
          removedFields,
          ipAddress: context.ipAddress,
          userAgent: context.userAgent,
        })
      }

      // Логирование производительности
      if (FEATURE_FLAGS.SUPPLY_DATA_SECURITY.enabled) {
        SecurityLogger.logFilteringPerformance({
          operation: 'filterSupplyOrder',
          duration: Date.now() - startTime,
          recordsFiltered: 1,
          fieldsRemoved: removedFields.length,
          cacheHit: false, // TODO: добавить кеширование
        })
      }

      return {
        data: filteredOrder,
        filtered,
        removedFields,
        accessLevel,
      }
    } catch (error) {
      SecurityLogger.logSecurityError(error as Error, {
        userId: context.user?.id || 'unknown',
        organizationType: context.user?.organizationType || context.organizationType || 'SELLER',
        orderId: order.id,
      })
      throw error
    }
  }

  /**
   * SELLER видит всю информацию по своим поставкам
   */
  private static filterForSeller(
    order: SupplyOrder,
    organizationId: string,
  ): { data: FilteredSupplyOrder; removedFields: string[]; accessLevel: DataAccessLevel } {
    // Проверка принадлежности заказа
    if (order.organizationId !== organizationId) {
      throw new GraphQLError('Access denied to this supply order', {
        extensions: { code: 'FORBIDDEN' },
      })
    }

    // Селлер видит всю информацию своего заказа
    return {
      data: { ...order },
      removedFields: [],
      accessLevel: 'FULL',
    }
  }

  /**
   * WHOLESALE видит только свои товары без рецептуры
   */
  private static filterForWholesale(
    order: SupplyOrder,
    organizationId: string,
  ): { data: FilteredSupplyOrder; removedFields: string[]; accessLevel: DataAccessLevel } {
    // Фильтруем только позиции данного поставщика
    console.warn(`[DEBUG] filterForWholesale: organizationId=${organizationId}, items:`, 
      order.items.map(item => ({
        productId: item.productId,
        productOrgId: item.product?.organizationId,
        hasProduct: !!item.product,
      })),
    )
    
    const myItems = order.items.filter((item) => item.product.organizationId === organizationId)
    
    console.warn(`[DEBUG] filterForWholesale: myItems.length=${myItems.length}`)

    if (myItems.length === 0) {
      throw new GraphQLError('No items from your organization in this order', {
        extensions: { code: 'FORBIDDEN' },
      })
    }

    const removedFields = [
      'totalAmount',
      'fulfillmentServicePrice',
      'logisticsPrice',
      'recipe',
      'services',
      'fulfillmentConsumables',
      'sellerConsumables',
    ]

    const filteredOrder: FilteredSupplyOrder = {
      id: order.id,
      organizationId: order.organizationId, // Обязательное поле
      partnerId: order.partnerId, // Обязательное поле  
      partner: order.partner || { id: order.partnerId, name: 'Partner' }, // Обязательное поле
      organization: order.organization || { id: order.organizationId, name: 'Organization' }, // Обязательное поле
      status: order.status, // Обязательное поле
      deliveryDate: order.deliveryDate, // Обязательное поле
      totalAmount: order.items
        .filter((item) => item.product.organizationId === organizationId)
        .reduce((sum, item) => sum + (item.price || 0) * item.quantity, 0), // Только сумма своих товаров
      totalItems: myItems.length, // Обязательное поле
      createdAt: order.createdAt, // Обязательное поле
      updatedAt: order.updatedAt, // Обязательное поле
      routes: order.routes || [], // Обязательное поле

      items: myItems.map((item) => ({
        id: item.id,
        productId: item.product.id, // Обязательное поле GraphQL
        product: {
          id: item.product.id,
          name: item.product.name,
          article: item.product.article || 'N/A', // Обязательное поле GraphQL
          price: item.product.price || 0, // Обязательное поле GraphQL
          quantity: item.product.quantity || 0, // Обязательное поле GraphQL
          images: item.product.images || [], // Обязательное поле GraphQL
          isActive: item.product.isActive !== false, // Обязательное поле GraphQL
          createdAt: item.product.createdAt || new Date().toISOString(), // Обязательное поле GraphQL
          updatedAt: item.product.updatedAt || new Date().toISOString(), // Обязательное поле GraphQL
          organization: item.product.organization || { // Обязательное поле GraphQL
            id: item.product.organizationId,
            inn: 'N/A',
            name: 'Organization',
            type: 'WHOLESALE',
          },
          organizationId: item.product.organizationId,
        },
        quantity: item.quantity,
        price: item.price, // Поставщик видит свою цену
        totalPrice: (item.price || 0) * item.quantity, // Обязательное поле GraphQL
        // Убираем рецептуру
        recipe: undefined,
      })),

      // Показываем параметры поставки для логистики
      packagesCount: order.packagesCount,
      volume: order.volume,
      readyDate: order.readyDate,
      notes: order.notes,
    }

    return {
      data: filteredOrder,
      removedFields,
      accessLevel: 'PARTIAL',
    }
  }

  /**
   * FULFILLMENT видит рецептуру, но не видит закупочные цены
   */
  private static filterForFulfillment(
    order: SupplyOrder,
    organizationId: string,
  ): { data: FilteredSupplyOrder; removedFields: string[]; accessLevel: DataAccessLevel } {
    // Проверка принадлежности заказа фулфилменту
    if (order.fulfillmentCenterId !== organizationId) {
      throw new GraphQLError('Access denied to this supply order', {
        extensions: { code: 'FORBIDDEN' },
      })
    }

    const removedFields = ['productPrice', 'sellerConsumables.price', 'items.price']

    const filteredOrder: FilteredSupplyOrder = {
      id: order.id,
      organizationId: order.organizationId, // Обязательное поле
      partnerId: order.partnerId, // Обязательное поле  
      partner: order.partner || { id: order.partnerId, name: 'Partner' }, // Обязательное поле
      organization: order.organization || { id: order.organizationId, name: 'Organization' }, // Обязательное поле
      status: order.status, // Обязательное поле
      deliveryDate: order.deliveryDate, // Обязательное поле
      totalAmount: order.totalAmount || 0, // Обязательное поле
      totalItems: order.totalItems, // Обязательное поле
      createdAt: order.createdAt, // Обязательное поле
      updatedAt: order.updatedAt, // Обязательное поле
      routes: order.routes || [], // Обязательное поле

      items: order.items.map((item) => ({
        id: item.id,
        productId: item.product.id, // Обязательное поле GraphQL
        product: {
          id: item.product.id,
          name: item.product.name,
          article: item.product.article || 'N/A', // Обязательное поле GraphQL
          price: item.product.price || 0, // Обязательное поле GraphQL
          quantity: item.product.quantity || 0, // Обязательное поле GraphQL
          images: item.product.images || [], // Обязательное поле GraphQL
          isActive: item.product.isActive !== false, // Обязательное поле GraphQL
          createdAt: item.product.createdAt || new Date().toISOString(), // Обязательное поле GraphQL
          updatedAt: item.product.updatedAt || new Date().toISOString(), // Обязательное поле GraphQL
          organization: item.product.organization || { // Обязательное поле GraphQL
            id: item.product.organizationId,
            inn: 'N/A',
            name: 'Organization',
            type: 'WHOLESALE',
          },
          organizationId: item.product.organizationId,
        },
        quantity: item.quantity,
        // Скрываем закупочную цену
        price: null,
        totalPrice: 0, // Фулфилмент не видит общую стоимость товаров
        // Оставляем рецептуру, но фильтруем цены расходников селлера
        recipe: item.recipe
          ? {
              services: item.recipe.services,
              fulfillmentConsumables: item.recipe.fulfillmentConsumables, // Свои расходники с ценами
              sellerConsumables: item.recipe.sellerConsumables?.map((c) => ({
                id: c.id,
                name: c.name,
                quantity: c.quantity,
                // НЕ показываем цену расходников селлера
                pricePerUnit: undefined,
                price: undefined,
              })),
            }
          : undefined,
      })),

      // Показываем только свою часть финансов
      totalAmount: this.calculateFulfillmentTotal(order),
      fulfillmentServicePrice: order.fulfillmentServicePrice,
      logisticsPrice: order.logisticsPrice, // Для планирования

      // Параметры поставки
      packagesCount: order.packagesCount,
      volume: order.volume,
      readyDate: order.readyDate,
      notes: order.notes,
    }

    return {
      data: filteredOrder,
      removedFields,
      accessLevel: 'PARTIAL',
    }
  }

  /**
   * LOGIST видит только информацию о доставке
   */
  private static filterForLogist(
    order: SupplyOrder,
    organizationId: string,
  ): { data: FilteredSupplyOrder; removedFields: string[]; accessLevel: DataAccessLevel } {
    // Проверка назначения логистики
    if (order.logisticsPartnerId !== organizationId) {
      throw new GraphQLError('Access denied to this supply order', {
        extensions: { code: 'FORBIDDEN' },
      })
    }

    const removedFields = [
      'items',
      'recipe',
      'productPrice',
      'fulfillmentServicePrice',
      // Убрали organizationId из removedFields - логистика должна знать заказчика
      'fulfillmentCenterId',
    ]

    const filteredOrder: FilteredSupplyOrder = {
      id: order.id,
      organizationId: order.organizationId, // Обязательное поле - логистика должна знать заказчика
      partnerId: order.partnerId, // Обязательное поле
      partner: order.partner || { id: order.partnerId, name: 'Partner' }, // Обязательное поле
      organization: order.organization || { id: order.organizationId, name: 'Organization' }, // Обязательное поле
      status: order.status, // Обязательное поле
      deliveryDate: order.deliveryDate, // Обязательное поле
      totalAmount: order.logisticsPrice || 0, // Только стоимость логистики
      totalItems: 0, // Логистика не видит детали товаров
      createdAt: order.createdAt, // Обязательное поле
      updatedAt: order.updatedAt, // Обязательное поле
      items: [], // Обязательное поле - пустой массив для логистики

      // Маршрутная информация
      routes: order.routes?.map((route) => ({
        from: route.from,
        fromAddress: route.fromAddress,
        to: route.to,
        toAddress: route.toAddress,
        packagesCount: route.packagesCount,
        volume: route.volume,
      })),

      // Только логистическая информация
      logisticsPrice: order.logisticsPrice,
      totalAmount: order.logisticsPrice, // Только своя сумма
      packagesCount: order.packagesCount,
      volume: order.volume,

      // Скрываем все коммерческие данные
      items: [], // Не показываем товары
    }

    return {
      data: filteredOrder,
      removedFields,
      accessLevel: 'PARTIAL',
    }
  }

  /**
   * Расчет суммы для фулфилмента (только их часть)
   */
  private static calculateFulfillmentTotal(order: SupplyOrder): number {
    let total = 0

    // Услуги фулфилмента
    total += Number(order.fulfillmentServicePrice || 0)

    // Логистика (для планирования)
    total += Number(order.logisticsPrice || 0)

    // Расходники фулфилмента
    order.items.forEach((item) => {
      if (item.recipe?.fulfillmentConsumables) {
        item.recipe.fulfillmentConsumables.forEach((consumable) => {
          total += (consumable.pricePerUnit || 0) * consumable.quantity
        })
      }
    })

    return total
  }
}
