import { ref, computed, onMounted, onUnmounted, readonly } from 'vue'
import { useMarketStore } from '../stores/market'
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
import { config } from '@/lib/config'
import type { NostrmarketService } from '../services/nostrmarketService'
import { nip04 } from 'nostr-tools'
import { useAsyncOperation } from '@/core/composables/useAsyncOperation'
import { auth } from '@/composables/useAuthService'

// Nostr event kinds for market functionality
const MARKET_EVENT_KINDS = {
  MARKET: 30019,
  STALL: 30017,
  PRODUCT: 30018
} as const

export function useMarket() {
  const marketStore = useMarketStore()
  const relayHub = injectService(SERVICE_TOKENS.RELAY_HUB) as any
  const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE) as any
  const nostrmarketService = injectService(SERVICE_TOKENS.NOSTRMARKET_SERVICE) as NostrmarketService

  if (!relayHub) {
    throw new Error('RelayHub not available. Make sure base module is installed.')
  }

  if (!authService) {
    throw new Error('AuthService not available. Make sure base module is installed.')
  }

  // Register market DM handler with chat service (if available)
  const registerMarketMessageHandler = () => {
    try {
      // Try to get the chat service (it might not be available if chat module isn't loaded)
      const chatService = (globalThis as any).chatService
      if (chatService && chatService.setMarketMessageHandler) {
        chatService.setMarketMessageHandler(handleOrderDM)
        console.log('🛒 Registered market message handler with chat service')
      } else {
        console.log('🛒 Chat service not available, market will use its own DM subscription')
      }
    } catch (error) {
      console.log('🛒 Could not register with chat service:', error)
    }
  }

  // Async operations
  const marketOperation = useAsyncOperation()
  const connectionOperation = useAsyncOperation()
  
  // State
  const isConnected = ref(false)
  const activeMarket = computed(() => marketStore.activeMarket)
  const markets = computed(() => marketStore.markets)
  const stalls = computed(() => marketStore.stalls)
  const products = computed(() => marketStore.products)
  const orders = computed(() => marketStore.orders)

  // Connection state
  const connectionStatus = computed(() => {
    if (connectionOperation.isLoading.value) return 'connecting'
    if (isConnected.value) return 'connected'
    if (connectionOperation.error.value || authService.error) return 'error'
    return 'disconnected'
  })

  // Load market from naddr
  const loadMarket = async (naddr: string) => {
    return await marketOperation.execute(async () => {
      // Parse naddr to get market data
      const marketData = {
        identifier: naddr.split(':')[2] || 'default',
        pubkey: naddr.split(':')[1] || authService.user.value?.pubkey || ''
      }

      if (!marketData.pubkey) {
        throw new Error('No pubkey available for market')
      }

      await loadMarketData(marketData)
      return marketData
    }, {
      errorMessage: 'Failed to load market'
    })
  }

  // Load market data from Nostr events
  const loadMarketData = async (marketData: any) => {
    try {
      console.log('🛒 Loading market data for:', { identifier: marketData.identifier, pubkey: marketData.pubkey?.slice(0, 8) })
      
      // Check if we can query events (relays are connected)
      if (!isConnected.value) {
        console.log('🛒 Not connected to relays, creating default market')
        // Create default market without trying to fetch from Nostr
        const market = {
          d: marketData.identifier,
          pubkey: marketData.pubkey,
          relays: config.nostr.relays,
          selected: true,
          opts: {
            name: 'Demo Market (Offline)',
            description: 'Demo market running in offline mode',
            merchants: [],
            ui: {}
          }
        }
        
        marketStore.addMarket(market)
        marketStore.setActiveMarket(market)
        return
      }
      
      // Load market data from Nostr events
      // Fetch market configuration event
      const events = await relayHub.queryEvents([
        {
          kinds: [MARKET_EVENT_KINDS.MARKET],
          authors: [marketData.pubkey],
          '#d': [marketData.identifier]
        }
      ])
      
      console.log('🛒 Found', events.length, 'market events')

              // Process market events

      if (events.length > 0) {
        const marketEvent = events[0]
                  // Process market event

        const market = {
          d: marketData.identifier,
          pubkey: marketData.pubkey,
          relays: config.nostr.relays,
          selected: true,
          opts: JSON.parse(marketEvent.content)
        }

        marketStore.addMarket(market)
        marketStore.setActiveMarket(market)
      } else {
        // No market events found, create default
        // Create a default market if none exists
        const market = {
          d: marketData.identifier,
          pubkey: marketData.pubkey,
          relays: config.nostr.relays,
          selected: true,
          opts: {
            name: `${import.meta.env.VITE_APP_NAME} Market`,
            description: 'A communal market to sell your goods',
            merchants: [],
            ui: {}
          }
        }

        marketStore.addMarket(market)
        marketStore.setActiveMarket(market)
      }

    } catch (err) {
      // Don't throw error, create default market instead
      const market = {
        d: marketData.identifier,
        pubkey: marketData.pubkey,
        relays: config.nostr.relays,
        selected: true,
        opts: {
          name: 'Default Market',
          description: 'A default market',
          merchants: [],
          ui: {}
        }
      }

      marketStore.addMarket(market)
      marketStore.setActiveMarket(market)
    }
  }

  // Load stalls from market merchants
  const loadStalls = async () => {
    try {
      // Get the active market to filter by its merchants
      const activeMarket = marketStore.activeMarket
      if (!activeMarket) {
        return
      }

              const merchants = [...(activeMarket.opts.merchants || [])]
        
        if (merchants.length === 0) {
          return
        }

      // Fetch stall events from market merchants only
      const events = await relayHub.queryEvents([
        {
          kinds: [MARKET_EVENT_KINDS.STALL],
          authors: merchants
        }
      ])
      
      console.log('🛒 Found', events.length, 'stall events for', merchants.length, 'merchants')

              // Process stall events

      // Group events by stall ID and keep only the most recent version
      const stallGroups = new Map<string, any[]>()
      events.forEach((event: any) => {
        const stallId = event.tags.find((tag: any) => tag[0] === 'd')?.[1]
        if (stallId) {
          if (!stallGroups.has(stallId)) {
            stallGroups.set(stallId, [])
          }
          stallGroups.get(stallId)!.push(event)
        }
      })

      // Process each stall group
      stallGroups.forEach((stallEvents, stallId) => {
        // Sort by created_at and take the most recent
        const latestEvent = stallEvents.sort((a: any, b: any) => b.created_at - a.created_at)[0]
        
        try {
          const stallData = JSON.parse(latestEvent.content)
          const stall = {
            id: stallId,
            pubkey: latestEvent.pubkey,
            name: stallData.name || 'Unnamed Stall',
            description: stallData.description || '',
            created_at: latestEvent.created_at,
            ...stallData
          }
          
          marketStore.addStall(stall)
        } catch (err) {
          // Silently handle parse errors
        }
      })

    } catch (err) {
      // Silently handle stall loading errors
    }
  }

  // Load products from market stalls
  const loadProducts = async () => {
    try {
      const activeMarket = marketStore.activeMarket
      if (!activeMarket) {
        return
      }

      const merchants = [...(activeMarket.opts.merchants || [])]
              if (merchants.length === 0) {
          return
        }

      // Fetch product events from market merchants
      const events = await relayHub.queryEvents([
        {
          kinds: [MARKET_EVENT_KINDS.PRODUCT],
          authors: merchants
        }
      ])
      
      console.log('🛒 Found', events.length, 'product events for', merchants.length, 'merchants')

              // Process product events

      // Group events by product ID and keep only the most recent version
      const productGroups = new Map<string, any[]>()
      events.forEach((event: any) => {
        const productId = event.tags.find((tag: any) => tag[0] === 'd')?.[1]
        if (productId) {
          if (!productGroups.has(productId)) {
            productGroups.set(productId, [])
          }
          productGroups.get(productId)!.push(event)
        }
      })

      // Process each product group
      productGroups.forEach((productEvents, productId) => {
        // Sort by created_at and take the most recent
        const latestEvent = productEvents.sort((a: any, b: any) => b.created_at - a.created_at)[0]
        
        try {
          const productData = JSON.parse(latestEvent.content)
          const product = {
            id: productId,
            stall_id: productData.stall_id || 'unknown',
            stallName: productData.stallName || 'Unknown Stall',
            name: productData.name || 'Unnamed Product',
            description: productData.description || '',
            price: productData.price || 0,
            currency: productData.currency || 'sats',
            quantity: productData.quantity || 1,
            images: productData.images || [],
            categories: productData.categories || [],
            createdAt: latestEvent.created_at,
            updatedAt: latestEvent.created_at
          }
          
          marketStore.addProduct(product)
        } catch (err) {
          // Silently handle parse errors
        }
      })

    } catch (err) {
      // Silently handle product loading errors
    }
  }


  // Subscribe to market updates
  const subscribeToMarketUpdates = (): (() => void) | null => {
    try {
      const activeMarket = marketStore.activeMarket
      if (!activeMarket) {
        return null
      }

      // Subscribe to market events
      const unsubscribe = relayHub.subscribe({
        id: `market-${activeMarket.d}`,
        filters: [
          { kinds: [MARKET_EVENT_KINDS.MARKET] },
          { kinds: [MARKET_EVENT_KINDS.STALL] },
          { kinds: [MARKET_EVENT_KINDS.PRODUCT] }
        ],
        onEvent: (event: any) => {
          handleMarketEvent(event)
        }
      })

      return unsubscribe
    } catch (error) {
      return null
    }
  }

  // Note: Order DMs are now handled by the chat service forwarding mechanism
  // This method is deprecated and should not be called
  const subscribeToOrderUpdates = (): (() => void) | null => {
    console.log('🔔 Order updates are now handled by chat service forwarding')
    return null
  }

  // Handle incoming order DMs (payment requests, status updates)
  const handleOrderDM = async (event: any) => {
    try {
      console.log('🔔 Received order-related DM:', event.id, 'from:', event.pubkey.slice(0, 8))
      
      // Check both injected auth service AND global auth composable
      const hasAuthService = authService.user.value?.prvkey
      const hasGlobalAuth = auth.currentUser.value?.prvkey
      
      const userPrivkey = hasAuthService ? authService.user.value.prvkey : auth.currentUser.value?.prvkey
      const userPubkey = hasAuthService ? authService.user.value.pubkey : auth.currentUser.value?.pubkey
      
      if (!userPrivkey || !userPubkey) {
        console.warn('Cannot decrypt DM: no user private key available', {
          hasAuthService: !!hasAuthService,
          hasGlobalAuth: !!hasGlobalAuth,
          authServicePrivkey: !!authService.user.value?.prvkey,
          globalAuthPrivkey: !!auth.currentUser.value?.prvkey
        })
        return
      }
      
      console.log('🔐 Market DM decryption auth check:', {
        hasAuthService: !!hasAuthService,
        hasGlobalAuth: !!hasGlobalAuth,
        usingAuthService: !!hasAuthService,
        userPubkey: userPubkey.substring(0, 10) + '...'
      })

      console.log('🔓 Attempting to decrypt DM with private key available')

      // Decrypt the DM content
      const decryptedContent = await nip04.decrypt(userPrivkey, event.pubkey, event.content)
      console.log('🔓 Decrypted DM content:', decryptedContent)

      // Parse the decrypted content as JSON
      const messageData = JSON.parse(decryptedContent)
      console.log('📨 Parsed message data:', messageData)

      // Handle different types of messages
      switch (messageData.type) {
        case 1: // Payment request
          console.log('💰 Processing payment request for order:', messageData.id)
          await nostrmarketService.handlePaymentRequest(messageData)
          console.log('✅ Payment request processed successfully')
          break
        case 2: // Order status update  
          console.log('📦 Processing order status update for order:', messageData.id)
          await nostrmarketService.handleOrderStatusUpdate(messageData)
          console.log('✅ Order status update processed successfully')
          break
        default:
          console.log('❓ Unknown message type:', messageData.type)
      }
    } catch (error) {
      console.error('Failed to handle order DM:', error)
    }
  }

  // Handle incoming market events
  const handleMarketEvent = (event: any) => {
    // Process market event

    switch (event.kind) {
      case MARKET_EVENT_KINDS.MARKET:
        // Handle market updates
        break
      case MARKET_EVENT_KINDS.STALL:
        // Handle stall updates
        handleStallEvent(event)
        break
      case MARKET_EVENT_KINDS.PRODUCT:
        // Handle product updates
        handleProductEvent(event)
        break
    }
  }

  // Process pending products (products without stalls)
  const processPendingProducts = () => {
    const productsWithoutStalls = products.value.filter(product => {
      // Check if product has a stall tag
      return !product.stall_id
    })

    if (productsWithoutStalls.length > 0) {
      // You could create default stalls or handle this as needed
    }
  }

  // Handle stall events
  const handleStallEvent = (event: any) => {
    try {
      const stallId = event.tags.find((tag: any) => tag[0] === 'd')?.[1]
      if (stallId) {
        const stallData = JSON.parse(event.content)
        const stall = {
          id: stallId,
          pubkey: event.pubkey,
          name: stallData.name || 'Unnamed Stall',
          description: stallData.description || '',
          created_at: event.created_at,
          ...stallData
        }
        
        marketStore.addStall(stall)
      }
    } catch (err) {
      // Silently handle stall event errors
    }
  }

  // Handle product events
  const handleProductEvent = (event: any) => {
    try {
      const productId = event.tags.find((tag: any) => tag[0] === 'd')?.[1]
      if (productId) {
        const productData = JSON.parse(event.content)
        const product = {
          id: productId,
          stall_id: productData.stall_id || 'unknown',
          stallName: productData.stallName || 'Unknown Stall',
          pubkey: event.pubkey,
          name: productData.name || 'Unnamed Product',
          description: productData.description || '',
          price: productData.price || 0,
          currency: productData.currency || 'sats',
          quantity: productData.quantity || 1,
          images: productData.images || [],
          categories: productData.categories || [],
          createdAt: event.created_at,
          updatedAt: event.created_at
        }
        
        marketStore.addProduct(product)
      }
    } catch (err) {
      // Silently handle product event errors
    }
  }

  // Publish a product
  const publishProduct = async (_productData: any) => {
    // Implementation would depend on your event creation logic
    // TODO: Implement product publishing
  }

  // Publish a stall
  const publishStall = async (_stallData: any) => {
    // Implementation would depend on your event creation logic
    // TODO: Implement stall publishing
  }

  // Connect to market
  const connectToMarket = async () => {
    return await connectionOperation.execute(async () => {
      console.log('🛒 Checking RelayHub connection...')
      // Use existing relay hub connection (should already be connected by base module)
      isConnected.value = relayHub.isConnected.value
      console.log('🛒 RelayHub connected:', isConnected.value)

      if (!isConnected.value) {
        console.warn('🛒 RelayHub not connected - this is expected if authentication is not complete')
        // Don't try to connect here - let the base module handle connections
        // Just proceed with offline/demo mode
        console.log('🛒 Proceeding in offline mode')
      }

      console.log('🛒 Market connected successfully')
      
      // Register market message handler with chat service
      registerMarketMessageHandler()
      
      // Load market data
      console.log('🛒 Loading basic market data...')
      await loadMarketData({
        identifier: 'default',
        pubkey: authService.user.value?.pubkey || ''
      })

      // Load stalls and products only if connected
      if (isConnected.value) {
        console.log('🛒 Loading stalls...')
        await loadStalls()
        console.log('🛒 Loading products...')
        await loadProducts()
      } else {
        console.log('🛒 Skipping stalls/products loading - not connected to relays')
      }

      // Subscribe to updates
      console.log('🛒 Subscribing to market updates...')
      subscribeToMarketUpdates()
      
      // Note: Order-related DMs are now handled by chat service forwarding
      // No need for separate subscription
      
      return { isConnected: isConnected.value }
    }, {
      errorMessage: 'Failed to connect to market'
    })
  }

  // Disconnect from market
  const disconnectFromMarket = () => {
    isConnected.value = false
    marketOperation.clear()
    connectionOperation.clear()
    // Market disconnected
  }

  // Initialize market on mount
  onMounted(async () => {
    if (relayHub.isConnected.value) {
      await connectToMarket()
    }
  })

  // Cleanup on unmount
  onUnmounted(() => {
    disconnectFromMarket()
  })

  return {
    // State
    isLoading: readonly(marketOperation.isLoading),
    error: readonly(marketOperation.error),
    isConnecting: readonly(connectionOperation.isLoading),
    connectionError: readonly(connectionOperation.error),
    isConnected: readonly(isConnected),
    connectionStatus: readonly(connectionStatus),
    activeMarket: readonly(activeMarket),
    markets: readonly(markets),
    stalls: readonly(stalls),
    products: readonly(products),
    orders: readonly(orders),

    // Actions
    loadMarket,
    connectToMarket,
    disconnectFromMarket,
    processPendingProducts,
    publishProduct,
    publishStall,
    subscribeToMarketUpdates,
    subscribeToOrderUpdates
  }
} 
