import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
import { wrapHandler, logError } from '../_shared/error-handler.ts'
import { fetchProducts, fetchOrders, fetchCustomers, fetchCategory } from '../_shared/shoprenter-client.ts'
import { detectCountryCode } from '../_shared/phone-formatter.ts'
import { cleanHtmlContent } from '../_shared/html-cleaner.ts'
import {
  collectionExists,
  createCollection,
  upsertPoints,
  deletePointsByFilter,
  scrollPoints,
  getCollectionName,
  generatePointId,
  initializeStoreCollections,
  generateEmbeddingBatch,
  createProductText,
  createOrderText,
  createCustomerText,
  QdrantPoint
} from '../_shared/qdrant-client.ts'

const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
}

/**
 * Extract category ID from ShopRenter category href URL
 * Example: "http://shopname.api.myshoprenter.hu/categories/Y2F0ZWdvcnktY2F0ZWdvcnlfaWQ9NTU=" -> "Y2F0ZWdvcnktY2F0ZWdvcnlfaWQ9NTU="
 */
function extractCategoryId(categoryHref: string): string | null {
  if (!categoryHref) return null
  const parts = categoryHref.split('/')
  return parts[parts.length - 1] || null
}

/**
 * Extract numeric category ID from base64-encoded category ID
 * Example: "Y2F0ZWdvcnktY2F0ZWdvcnlfaWQ9MjA2" -> "206"
 */
function extractNumericCategoryId(base64CategoryId: string): string | null {
  try {
    const decoded = atob(base64CategoryId)
    // Format: "category-category_id=206"
    const match = decoded.match(/category_id=(\d+)/)
    return match ? match[1] : null
  } catch (error) {
    console.error('Failed to decode category ID:', base64CategoryId, error)
    return null
  }
}

/**
 * Extract categories from ShopRenter product and return array with ID and name
 * Returns: [{ id: "206", name: "Category Name" }, ...]
 */
async function extractProductCategories(product: any, categoryCache: Map<string, string>): Promise<Array<{ id: string; name: string }>> {
  const categories: Array<{ id: string; name: string }> = []
  const categoryRelations = product.productCategoryRelations || []

  for (const rel of categoryRelations) {
    const categoryId = extractCategoryId(rel.category?.href)
    if (categoryId) {
      const numericId = extractNumericCategoryId(categoryId)
      if (numericId && categoryCache.has(categoryId)) {
        categories.push({
          id: numericId,
          name: categoryCache.get(categoryId)!
        })
      }
    }
  }

  return categories
}

/**
 * Fetch and process category details from ShopRenter API
 * Returns a text representation: "CategoryName - Description" (HTML cleaned)
 */
async function fetchCategoryText(storeId: string, categoryId: string): Promise<string | null> {
  try {
    const categoryData = await fetchCategory(storeId, categoryId)

    // Extract first language description (Hungarian is typically first)
    const categoryDesc = categoryData.categoryDescriptions?.[0]
    if (!categoryDesc) return null

    const name = categoryDesc.name || ''
    const description = categoryDesc.description || ''

    // Clean HTML from description
    const cleanDesc = cleanHtmlContent(description)

    // Concatenate name and description
    if (name && cleanDesc) {
      return `${name} - ${cleanDesc}`
    } else if (name) {
      return name
    } else if (cleanDesc) {
      return cleanDesc
    }

    return null
  } catch (error) {
    console.error(`[ShopRenter] Failed to fetch category ${categoryId}:`, error)
    return null
  }
}

/**
 * Extract and process tags from ShopRenter productTags array
 * ShopRenter format: [{ tags: "tag1,tag2,tag3" }]
 * Returns: ["tag1", "tag2", "tag3"]
 */
function extractTags(productTags: any[]): string[] {
  if (!productTags || !Array.isArray(productTags)) return []

  const allTags: string[] = []

  for (const tagObj of productTags) {
    // productTags[].tags is a comma-separated string
    if (tagObj.tags && typeof tagObj.tags === 'string') {
      const tags = tagObj.tags.split(',').map((t: string) => t.trim()).filter(Boolean)
      allTags.push(...tags)
    }
  }

  // Remove duplicates
  return [...new Set(allTags)]
}

// Log Qdrant sync operation
async function logQdrantSync(
  supabaseAdmin: any,
  storeId: string,
  syncType: string,
  collectionName: string,
  operation: string,
  itemsProcessed: number,
  itemsSucceeded: number,
  itemsFailed: number,
  startedAt: Date,
  errorMessage?: string
): Promise<void> {
  try {
    await supabaseAdmin
      .from('qdrant_sync_logs')
      .insert({
        store_id: storeId,
        sync_type: syncType,
        collection_name: collectionName,
        operation,
        items_processed: itemsProcessed,
        items_succeeded: itemsSucceeded,
        items_failed: itemsFailed,
        error_message: errorMessage,
        started_at: startedAt.toISOString(),
        completed_at: new Date().toISOString(),
      })
  } catch (error) {
    console.error('[Qdrant] Failed to log sync operation:', error)
  }
}

// Sync products to Qdrant
async function syncProductsToQdrant(
  storeId: string,
  storeName: string,
  products: any[],
  supabaseAdmin: any
): Promise<{ synced: number; errors: number }> {
  const startTime = new Date()
  const collectionName = getCollectionName(storeName, 'products')

  // Filter out products without valid IDs (must have innerId)
  const validProducts = products.filter(p => p && p.innerId)

  if (validProducts.length === 0) {
    console.log('[Qdrant] No valid products to sync (all products missing innerId)')
    return { synced: 0, errors: 0 }
  }

  console.log(`[Qdrant] Syncing ${validProducts.length} products to ${collectionName}`)

  let synced = 0
  let errors = 0

  try {
    if (!(await collectionExists(collectionName))) {
      await createCollection(collectionName, [
        { field: 'store_id', type: 'keyword' },
        { field: 'product_id', type: 'keyword' },
        { field: 'platform', type: 'keyword' },
        { field: 'active', type: 'keyword' },
        { field: 'price', type: 'float' },
        { field: 'sku', type: 'keyword' },
      ])
    }

    // Get existing product IDs from Qdrant to detect deletions and changes
    const existingPoints = await scrollPoints(collectionName, {
      must: [{ key: 'store_id', match: { value: storeId } }]
    }, 1000)

    // Build a map of existing products for efficient lookup
    const existingProductsMap = new Map(
      existingPoints.points.map((p: any) => [p.payload?.product_id, p])
    )

    const existingProductIds = new Set(existingProductsMap.keys())
    const currentProductIds = new Set(validProducts.map(p => p.innerId.toString()))

    // Find deleted products
    const deletedProductIds = Array.from(existingProductIds).filter(
      id => !currentProductIds.has(id)
    )

    // Delete removed products from Qdrant
    if (deletedProductIds.length > 0) {
      console.log(`[Qdrant] Deleting ${deletedProductIds.length} removed products`)
      await deletePointsByFilter(collectionName, {
        must: [
          { key: 'store_id', match: { value: storeId } },
          { key: 'product_id', match: { any: deletedProductIds } }
        ]
      })
    }

    // Helper function to check if product data has changed
    const hasProductChanged = (product: any, existingPoint: any): boolean => {
      if (!existingPoint) return true // New product

      const payload = existingPoint.payload
      const productDesc = product.productDescriptions?.[0] || {}

      // Compare key fields that would affect the embedding
      return (
        payload.name !== (productDesc.name || product.name) ||
        payload.sku !== product.sku ||
        payload.price !== parseFloat(product.price || '0') ||
        payload.description !== (productDesc.description || null) ||
        payload.short_description !== (productDesc.shortDescription || null) ||
        payload.stock !== parseInt(product.stock1 || '0') ||
        payload.status !== (product.status === '1' ? 'active' : 'inactive')
      )
    }

    // Separate products into new/changed vs unchanged
    const productsNeedingEmbedding: any[] = []
    const productsToReuse: { product: any; existingPoint: any }[] = []

    validProducts.forEach(product => {
      const productId = product.innerId.toString()
      const existingPoint = existingProductsMap.get(productId)

      // Check if product needs new embedding (changed OR missing/invalid vector)
      if (hasProductChanged(product, existingPoint) || !existingPoint?.vector || !Array.isArray(existingPoint.vector)) {
        productsNeedingEmbedding.push(product)
      } else {
        productsToReuse.push({ product, existingPoint })
      }
    })

    console.log(`[Qdrant] Products analysis: ${productsNeedingEmbedding.length} new/changed, ${productsToReuse.length} unchanged`)

    // Collect all unique category IDs from ALL products (both new/changed and reused)
    // This ensures we only fetch each category once per sync run
    const uniqueCategoryIds = new Set<string>()
    for (const product of validProducts) {
      const categoryRelations = product.productCategoryRelations || []
      for (const rel of categoryRelations) {
        const categoryId = extractCategoryId(rel.category?.href)
        if (categoryId) {
          uniqueCategoryIds.add(categoryId)
        }
      }
    }

    // Fetch all categories in parallel (with error handling for each)
    console.log(`[Qdrant] Fetching ${uniqueCategoryIds.size} unique categories...`)
    const categoryCache = new Map<string, string>()
    const categoryPromises = Array.from(uniqueCategoryIds).map(async (categoryId) => {
      const categoryText = await fetchCategoryText(storeId, categoryId)
      if (categoryText) {
        categoryCache.set(categoryId, categoryText)
      }
    })
    await Promise.all(categoryPromises)
    console.log(`[Qdrant] Fetched ${categoryCache.size} categories successfully`)

    // Generate text representations only for new/changed products
    const productTexts = productsNeedingEmbedding.map((product) => {
      // Extract first language description from productDescriptions array
      const productDesc = product.productDescriptions?.[0] || {}

      // Extract tags from productTags array (ShopRenter format: [{ tags: "tag1,tag2" }])
      const tags = extractTags(product.productTags || [])

      // Extract attributes from productAttributeExtend array
      const attributes = (product.productAttributeExtend || []).map((attr: any) => {
        if (attr.name && attr.value) {
          return { name: attr.name, options: attr.value }
        }
        return null
      }).filter(Boolean)

      // Extract categories and fetch their text representations
      const categoryTexts: string[] = []
      const categoryRelations = product.productCategoryRelations || []
      for (const rel of categoryRelations) {
        const categoryId = extractCategoryId(rel.category?.href)
        if (categoryId && categoryCache.has(categoryId)) {
          categoryTexts.push(categoryCache.get(categoryId)!)
        }
      }

      return createProductText({
        name: productDesc.name || product.name,
        description: productDesc.description || null,
        short_description: productDesc.shortDescription || null,
        sku: product.sku,
        categories: categoryTexts,
        tags: tags,
        attributes: attributes,
        price: product.price,
        meta_description: productDesc.metaDescription || null,
      })
    })

    // Generate embeddings only for new/changed products
    let embeddings: number[][] = []
    if (productTexts.length > 0) {
      console.log(`[Qdrant] Generating embeddings for ${productTexts.length} new/changed products...`)
      embeddings = await generateEmbeddingBatch(productTexts)
      console.log(`[Qdrant] Embeddings generated successfully`)
    } else {
      console.log(`[Qdrant] No new/changed products - skipping embedding generation`)
    }

    // Convert new/changed products to Qdrant points with embeddings
    const newPoints: QdrantPoint[] = productsNeedingEmbedding.map((product, index) => {
      // Extract first language description from productDescriptions array
      const productDesc = product.productDescriptions?.[0] || {}

      // Extract tags from productTags array (ShopRenter format: [{ tags: "tag1,tag2" }])
      const tags = extractTags(product.productTags || [])

      // Extract attributes from productAttributeExtend array
      const attributes = (product.productAttributeExtend || []).map((attr: any) => {
        if (attr.name && attr.value) {
          return { name: attr.name, value: attr.value }
        }
        return null
      }).filter(Boolean)

      // Extract categories and get their text representations
      const categoryTexts: string[] = []
      const categoryRelations = product.productCategoryRelations || []
      for (const rel of categoryRelations) {
        const categoryId = extractCategoryId(rel.category?.href)
        if (categoryId && categoryCache.has(categoryId)) {
          categoryTexts.push(categoryCache.get(categoryId)!)
        }
      }

      // Extract manufacturer info (filter out href)
      const manufacturer = product.manufacturer?.name || null

      return {
        id: generatePointId('shoprenter', storeId, product.innerId),
        vector: embeddings[index],
        payload: {
          // Basic identification
          store_id: storeId,
          product_id: product.innerId.toString(),
          platform: 'shoprenter',
          name: productDesc.name || product.name || null,
          sku: product.sku || null,

          // Pricing
          price: parseFloat(product.price) || 0,
          currency: 'HUF',

          // Descriptions (extracted from productDescriptions array)
          description: productDesc.description || null,
          short_description: productDesc.shortDescription || null,
          meta_description: productDesc.metaDescription || null,

          // Categorization (stored as text arrays for embedding)
          categories: categoryTexts,
          tags: tags,

          // Attributes
          attributes: attributes,

          // Images (filter out hrefs, keep only actual image data)
          main_image: product.allImages?.mainImage || null,
          image_alt: product.imageAlt || null,

          // Stock information
          stock: parseInt(product.stock1 || '0') || 0,
          stock_status: parseInt(product.stock1 || '0') > 0 ? 'instock' : 'outofstock',

          // Product status
          active: product.status === '1',
          status: product.status === '1' ? 'active' : 'inactive',

          // Additional fields
          manufacturer: manufacturer,
          model: product.modelNumber || null,
          weight: product.weight ? parseFloat(product.weight) : null,

          // Metadata
          synced_at: new Date().toISOString(),
        }
      }
    })

    // Create points for unchanged products (reuse existing embeddings and update metadata)
    const reusedPoints: QdrantPoint[] = productsToReuse.map(({ product, existingPoint }) => {
      const productDesc = product.productDescriptions?.[0] || {}
      const tags = extractTags(product.productTags || [])
      const attributes = (product.productAttributeExtend || []).map((attr: any) => {
        if (attr.name && attr.value) {
          return { name: attr.name, value: attr.value }
        }
        return null
      }).filter(Boolean)

      // Extract categories and get their text representations
      const categoryTexts: string[] = []
      const categoryRelations = product.productCategoryRelations || []
      for (const rel of categoryRelations) {
        const categoryId = extractCategoryId(rel.category?.href)
        if (categoryId && categoryCache.has(categoryId)) {
          categoryTexts.push(categoryCache.get(categoryId)!)
        }
      }

      const manufacturer = product.manufacturer?.name || null

      return {
        id: existingPoint.id,
        vector: existingPoint.vector,  // Reuse existing embedding
        payload: {
          ...existingPoint.payload,
          // Only update metadata fields that don't affect embeddings
          synced_at: new Date().toISOString(),
        }
      }
    })

    // Combine new and reused points
    const allPoints = [...newPoints, ...reusedPoints]

    if (allPoints.length > 0) {
      await upsertPoints(collectionName, allPoints)
      synced = allPoints.length
    }

    await logQdrantSync(
      supabaseAdmin,
      storeId,
      'products',
      collectionName,
      'upsert',
      products.length,
      synced,
      errors,
      startTime
    )

    console.log(`[Qdrant] Products sync complete: ${synced} total (${newPoints.length} new/changed, ${reusedPoints.length} unchanged), ${deletedProductIds.length} deleted`)
  } catch (error: any) {
    console.error('[Qdrant] Product sync error:', error)
    errors = products.length
    await logQdrantSync(
      supabaseAdmin,
      storeId,
      'products',
      collectionName,
      'upsert',
      products.length,
      synced,
      errors,
      startTime,
      error.message
    )
  }

  return { synced, errors }
}

// Sync orders to Qdrant
async function syncOrdersToQdrant(
  storeId: string,
  storeName: string,
  orders: any[],
  supabaseAdmin: any
): Promise<{ synced: number; errors: number }> {
  const startTime = new Date()
  const collectionName = getCollectionName(storeName, 'orders')

  // Filter out orders without valid IDs
  const validOrders = orders.filter(o => o && o.innerId)

  if (validOrders.length === 0) {
    console.log('[Qdrant] No valid orders to sync (all orders missing innerId)')
    return { synced: 0, errors: 0 }
  }

  console.log(`[Qdrant] Syncing ${validOrders.length} orders to ${collectionName}`)

  let synced = 0
  let errors = 0

  try {
    if (!(await collectionExists(collectionName))) {
      await createCollection(collectionName, [
        { field: 'store_id', type: 'keyword' },
        { field: 'order_id', type: 'keyword' },
        { field: 'platform', type: 'keyword' },
        { field: 'status', type: 'keyword' },
        { field: 'total_price', type: 'float' },
        { field: 'customer_email', type: 'keyword' },
        { field: 'customer_phone', type: 'keyword' },
        { field: 'billing_city', type: 'keyword' },
        { field: 'billing_country', type: 'keyword' },
        { field: 'shipping_city', type: 'keyword' },
        { field: 'shipping_country', type: 'keyword' },
      ])
    }

    // Get existing order IDs from Qdrant to detect deletions
    const existingPoints = await scrollPoints(collectionName, {
      must: [{ key: 'store_id', match: { value: storeId } }]
    }, 1000)

    const existingOrderIds = new Set(
      existingPoints.points.map((p: any) => p.payload?.order_id).filter(Boolean)
    )

    const currentOrderIds = new Set(validOrders.map(o => o.innerId.toString()))
    const deletedOrderIds = Array.from(existingOrderIds).filter(
      id => !currentOrderIds.has(id)
    )

    // Delete orders that no longer exist
    if (deletedOrderIds.length > 0) {
      console.log(`[Qdrant] Deleting ${deletedOrderIds.length} orders that no longer exist`)
      await deletePointsByFilter(collectionName, {
        must: [
          { key: 'store_id', match: { value: storeId } },
          { key: 'order_id', match: { any: deletedOrderIds } }
        ]
      })
      await logQdrantSync(
        supabaseAdmin,
        storeId,
        'orders',
        collectionName,
        'delete',
        deletedOrderIds.length,
        deletedOrderIds.length,
        0,
        startTime
      )
    }

    // Generate embeddings for all orders
    const orderTexts = validOrders.map(order => createOrderText(order))
    const embeddings = await generateEmbeddingBatch(orderTexts)

    // Create Qdrant points
    const points: QdrantPoint[] = validOrders.map((order, index) => {
      return {
        id: generatePointId('shoprenter', storeId, order.innerId),
        vector: embeddings[index],
        payload: {
          // Basic identification
          store_id: storeId,
          order_id: order.innerId.toString(),
          platform: 'shoprenter',
          order_number: order.orderNumber || order.innerId.toString(),

          // Customer information
          customer_name: `${order.firstname || ''} ${order.lastname || ''}`.trim() || null,
          customer_email: order.email || null,
          customer_phone: order.phone || null,

          // Billing address
          billing_address: {
            address1: order.billingAddress || null,
            city: order.billingCity || null,
            zip: order.billingZipCode || null,
            country: order.billingCountryName || null,
          },

          // Shipping address
          shipping_address: {
            address1: order.shippingAddress || null,
            city: order.shippingCity || null,
            zip: order.shippingZipCode || null,
            country: order.shippingCountryName || null,
          },

          // Pricing
          total_price: parseFloat(order.total || '0') || 0,
          currency: order.currency || 'HUF',

          // Status
          status: order.orderStatus?.name || 'unknown',

          // Order items
          line_items: order.orderProducts || [],

          // Metadata
          synced_at: new Date().toISOString(),
        }
      }
    })

    await upsertPoints(collectionName, points)
    synced = points.length

    await logQdrantSync(
      supabaseAdmin,
      storeId,
      'orders',
      collectionName,
      'upsert',
      orders.length,
      synced,
      errors,
      startTime
    )

    console.log(`[Qdrant] Orders sync complete: ${synced} synced, ${deletedOrderIds.length} deleted`)
  } catch (error: any) {
    console.error('[Qdrant] Order sync error:', error)
    errors = orders.length
    await logQdrantSync(
      supabaseAdmin,
      storeId,
      'orders',
      collectionName,
      'upsert',
      orders.length,
      synced,
      errors,
      startTime,
      error.message
    )
  }

  return { synced, errors }
}

// Sync customers to Qdrant
async function syncCustomersToQdrant(
  storeId: string,
  storeName: string,
  customers: any[],
  supabaseAdmin: any
): Promise<{ synced: number; errors: number }> {
  const startTime = new Date()
  const collectionName = getCollectionName(storeName, 'customers')

  // Filter out customers without valid IDs
  const validCustomers = customers.filter(c => c && c.innerId)

  if (validCustomers.length === 0) {
    console.log('[Qdrant] No valid customers to sync (all customers missing innerId)')
    return { synced: 0, errors: 0 }
  }

  console.log(`[Qdrant] Syncing ${validCustomers.length} customers to ${collectionName}`)

  let synced = 0
  let errors = 0

  try {
    if (!(await collectionExists(collectionName))) {
      await createCollection(collectionName, [
        { field: 'store_id', type: 'keyword' },
        { field: 'customer_id', type: 'keyword' },
        { field: 'platform', type: 'keyword' },
        { field: 'email', type: 'keyword' },
        { field: 'phone', type: 'keyword' },
        { field: 'city', type: 'keyword' },
        { field: 'country', type: 'keyword' },
      ])
    }

    // Get existing customer IDs from Qdrant to detect deletions
    const existingPoints = await scrollPoints(collectionName, {
      must: [{ key: 'store_id', match: { value: storeId } }]
    }, 1000)

    const existingCustomerIds = new Set(
      existingPoints.points.map((p: any) => p.payload?.customer_id).filter(Boolean)
    )

    const currentCustomerIds = new Set(validCustomers.map(c => c.innerId.toString()))
    const deletedCustomerIds = Array.from(existingCustomerIds).filter(
      id => !currentCustomerIds.has(id)
    )

    // Delete customers that no longer exist
    if (deletedCustomerIds.length > 0) {
      console.log(`[Qdrant] Deleting ${deletedCustomerIds.length} customers that no longer exist`)
      await deletePointsByFilter(collectionName, {
        must: [
          { key: 'store_id', match: { value: storeId } },
          { key: 'customer_id', match: { any: deletedCustomerIds } }
        ]
      })
      await logQdrantSync(
        supabaseAdmin,
        storeId,
        'customers',
        collectionName,
        'delete',
        deletedCustomerIds.length,
        deletedCustomerIds.length,
        0,
        startTime
      )
    }

    // Generate embeddings for all customers
    const customerTexts = validCustomers.map(customer => createCustomerText(customer))
    const embeddings = await generateEmbeddingBatch(customerTexts)

    // Create Qdrant points
    const points: QdrantPoint[] = validCustomers.map((customer, index) => {
      return {
        id: generatePointId('shoprenter', storeId, customer.innerId),
        vector: embeddings[index],
        payload: {
          // Basic identification
          store_id: storeId,
          customer_id: customer.innerId.toString(),
          platform: 'shoprenter',

          // Customer information
          first_name: customer.firstname || null,
          last_name: customer.lastname || null,
          email: customer.email || null,
          phone: customer.phone || null,

          // Address
          default_address: {
            address1: customer.shippingAddress || null,
            city: customer.shippingCity || null,
            zip: customer.shippingZipCode || null,
            country: customer.shippingCountryName || null,
          },

          // Billing address
          billing_address: {
            address1: customer.billingAddress || null,
            city: customer.billingCity || null,
            zip: customer.billingZipCode || null,
            country: customer.billingCountryName || null,
          },

          // Customer stats (if available)
          orders_count: customer.ordersCount || 0,
          total_spent: parseFloat(customer.totalSpent || '0') || 0,

          // Metadata
          synced_at: new Date().toISOString(),
        }
      }
    })

    await upsertPoints(collectionName, points)
    synced = points.length

    await logQdrantSync(
      supabaseAdmin,
      storeId,
      'customers',
      collectionName,
      'upsert',
      customers.length,
      synced,
      errors,
      startTime
    )

    console.log(`[Qdrant] Customers sync complete: ${synced} synced, ${deletedCustomerIds.length} deleted`)
  } catch (error: any) {
    console.error('[Qdrant] Customer sync error:', error)
    errors = customers.length
    await logQdrantSync(
      supabaseAdmin,
      storeId,
      'customers',
      collectionName,
      'upsert',
      customers.length,
      synced,
      errors,
      startTime,
      error.message
    )
  }

  return { synced, errors }
}

serve(wrapHandler('shoprenter-sync', async (req) => {
  if (req.method === 'OPTIONS') {
    return new Response('ok', { headers: corsHeaders })
  }

  try {
    // Get authorization header
    const authHeader = req.headers.get('authorization')
    if (!authHeader) {
      return new Response(
        JSON.stringify({ error: 'No authorization header' }),
        { status: 401, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
      )
    }

    const token = authHeader.replace('Bearer ', '')
    const supabaseUrl = Deno.env.get('SUPABASE_URL')!
    const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
    const supabaseAnonKey = Deno.env.get('SUPABASE_ANON_KEY')!

    // Get storeId from URL path
    const url = new URL(req.url)
    const pathParts = url.pathname.split('/')
    const storeId = pathParts[pathParts.length - 1]

    if (!storeId) {
      return new Response(
        JSON.stringify({ error: 'Store ID is required' }),
        { status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
      )
    }

    // Check if this is an internal call (service role key) or user call (JWT token)
    const isInternalCall = token === supabaseServiceKey
    let userId: string | null = null

    if (isInternalCall) {
      // Internal call from trigger-sync - use service role key to get store
      console.log('[ShopRenter] Internal call detected, using service role key')
      const supabaseAdmin = createClient(supabaseUrl, supabaseServiceKey)

      const { data: store, error: storeError } = await supabaseAdmin
        .from('stores')
        .select('id, user_id, store_name, platform_name, store_url, qdrant_sync_enabled')
        .eq('id', storeId)
        .eq('platform_name', 'shoprenter')
        .single()

      if (storeError || !store) {
        return new Response(
          JSON.stringify({ error: 'Store not found' }),
          { status: 404, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
        )
      }

      userId = store.user_id
    } else {
      // User call - validate JWT token
      console.log('[ShopRenter] User call detected, validating JWT token')
      const supabase = createClient(supabaseUrl, supabaseAnonKey)
      const { data: { user }, error: userError } = await supabase.auth.getUser(token)

      if (userError || !user) {
        return new Response(
          JSON.stringify({ error: 'Invalid token' }),
          { status: 401, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
        )
      }

      userId = user.id
    }

    // Now fetch store with proper authorization (include sync config)
    const supabaseAdmin = createClient(supabaseUrl, supabaseServiceKey)
    const { data: store, error: storeError } = await supabaseAdmin
      .from('stores')
      .select(`
        id,
        store_name,
        platform_name,
        store_url,
        qdrant_sync_enabled,
        store_sync_config (
          orders_access_policy,
          customers_access_policy
        )
      `)
      .eq('id', storeId)
      .eq('user_id', userId)
      .eq('platform_name', 'shoprenter')
      .single()

    if (storeError || !store) {
      return new Response(
        JSON.stringify({ error: 'Store not found or access denied' }),
        { status: 404, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
      )
    }

    // Detect country code from store URL for phone formatting
    const countryCode = detectCountryCode(store.store_url)
    console.log(`[ShopRenter] Detected country code: ${countryCode} for store: ${store.store_name}`)

    console.log(`[ShopRenter] Starting full sync for store ${storeId}`)

    // Check data access permissions
    // Get access policies from store_sync_config
    const { data: syncConfig } = await supabaseAdmin
      .from('store_sync_config')
      .select('products_access_policy, orders_access_policy, customers_access_policy')
      .eq('store_id', storeId)
      .single()

    // Only sync if policy is 'sync' (not 'api_only' or 'not_allowed')
    const canSyncProducts = syncConfig?.products_access_policy === 'sync'
    const canSyncOrders = syncConfig?.orders_access_policy === 'sync'
    const canSyncCustomers = syncConfig?.customers_access_policy === 'sync'
    const qdrantEnabled = store.qdrant_sync_enabled !== false

    console.log('[ShopRenter] Sync permissions:', {
      productsPolicy: syncConfig?.products_access_policy || 'not_configured',
      ordersPolicy: syncConfig?.orders_access_policy || 'not_configured',
      customersPolicy: syncConfig?.customers_access_policy || 'not_configured',
      products: canSyncProducts,
      orders: canSyncOrders,
      customers: canSyncCustomers,
      qdrant: qdrantEnabled
    })

    const syncStats = {
      products: { synced: 0, errors: 0 },
      orders: { synced: 0, errors: 0 },
      customers: { synced: 0, errors: 0 }
    }

    // supabaseAdmin already created above, reuse it

    // Initialize Qdrant collections if enabled
    if (qdrantEnabled) {
      try {
        await initializeStoreCollections(
          store.store_name,
          canSyncOrders,
          canSyncCustomers
        )
      } catch (error) {
        console.error('[Qdrant] Failed to initialize collections:', error)
      }
    }

    // Sync Products
    const allProducts: any[] = []
    let productSyncError: Error | null = null
    try {
      if (!canSyncProducts) {
        console.log('[ShopRenter] Product sync disabled by store permissions')
      } else {
        console.log('[ShopRenter] Syncing products...')
        let page = 0  // ShopRenter API uses zero-based pagination (starts at 0)
        let hasMore = true
        const limit = 50

        // Build cache of all unique category IDs and names across all products first
        const allProductsForCache: any[] = []
        const allUniqueCategories = new Set<string>()

        while (hasMore) {
          const productsData = await fetchProducts(storeId, page, limit)

          if (productsData.items && productsData.items.length > 0) {
            // Collect all products for Qdrant sync and cache processing
            allProducts.push(...productsData.items)
            allProductsForCache.push(...productsData.items)

            // Collect all unique category IDs for batch fetching
            for (const product of productsData.items) {
              const categoryRelations = product.productCategoryRelations || []
              for (const rel of categoryRelations) {
                const categoryId = extractCategoryId(rel.category?.href)
                if (categoryId) {
                  allUniqueCategories.add(categoryId)
                }
              }
            }

            // Check if there are more pages
            if (productsData.pagination && productsData.pagination.total) {
              const totalPages = Math.ceil(productsData.pagination.total / limit)
              hasMore = page < totalPages - 1  // Zero-based, so last page is totalPages - 1
            } else {
              hasMore = productsData.items.length === limit
            }

            page++
          } else {
            hasMore = false
          }
        }

        // Now fetch all unique categories in parallel
        console.log(`[ShopRenter] Fetching ${allUniqueCategories.size} unique categories for cache...`)
        const categoryCache = new Map<string, string>()
        if (allUniqueCategories.size > 0) {
          const categoryPromises = Array.from(allUniqueCategories).map(async (categoryId) => {
            try {
              const categoryText = await fetchCategoryText(storeId, categoryId)
              if (categoryText) {
                categoryCache.set(categoryId, categoryText)
              }
            } catch (error) {
              console.error(`Failed to fetch category ${categoryId}:`, error)
            }
          })
          await Promise.all(categoryPromises)
        }
        console.log(`[ShopRenter] Fetched ${categoryCache.size} categories successfully`)

        // Now process all products and cache them with proper category data and exclusion status
        const productsToCache = await Promise.all(
          allProductsForCache.map(async (product: any) => {
            const categories = await extractProductCategories(product, categoryCache)
            // Extract the correct name from productDescriptions (same logic as qdrant sync)
            const productDesc = product.productDescriptions?.[0] || {}
            const productName = productDesc.name || product.name || null

            // Check if product is excluded by category using database function
            const { data: categoryExcluded, error: categoryExclusionError } = await supabaseAdmin
              .rpc('is_product_excluded_by_category', {
                p_store_id: storeId,
                p_categories: categories,
                p_platform: 'shoprenter'
              })

            if (categoryExclusionError) {
              console.error(`[ShopRenter] Error checking category exclusion for product ${product.id}:`, categoryExclusionError)
            }

            // Check if product is individually excluded from cache
            const { data: existingProduct, error: existingError } = await supabaseAdmin
              .from('shoprenter_products_cache')
              .select('excluded')
              .eq('store_id', storeId)
              .eq('product_id', product.id)
              .single()

            if (existingError && existingError.code !== 'PGRST116') {
              console.error(`[ShopRenter] Error checking existing product exclusion for ${product.id}:`, existingError)
            }

            // Product is excluded if:
            // 1. Excluded by category, OR
            // 2. Individually excluded (from existing cache record)
            const isExcluded = categoryExcluded || (existingProduct?.excluded === true)

            return {
              store_id: storeId,
              product_id: product.id,
              inner_id: product.innerId,
              name: productName,
              sku: product.sku,
              categories: categories,  // Now stores [{ id: "206", name: "Category Name" }]
              excluded: isExcluded,
              last_synced_at: new Date().toISOString()
            }
          })
        )

        // Cache all products at once
        if (productsToCache.length > 0) {
          const { error: upsertError } = await supabaseAdmin
            .from('shoprenter_products_cache')
            .upsert(productsToCache, {
              onConflict: 'store_id,product_id'
            })

          if (upsertError) {
            console.error('[ShopRenter] Error caching products:', upsertError)
            syncStats.products.errors += productsToCache.length
          } else {
            syncStats.products.synced += productsToCache.length
          }
        }

        console.log(`[ShopRenter] Products synced: ${syncStats.products.synced}`)

        // Handle Qdrant sync with exclusion logic
        if (qdrantEnabled && allProducts.length > 0) {
          // Get excluded product IDs for Qdrant cleanup
          const excludedProductIds = productsToCache
            .filter(p => p.excluded)
            .map(p => p.product_id)

          // Filter products for Qdrant sync (only non-excluded)
          const productsForQdrant = allProducts.filter(product => {
            const productCacheItem = productsToCache.find(p => p.product_id === product.id)
            return productCacheItem && !productCacheItem.excluded
          })

          // Delete excluded products from Qdrant
          if (excludedProductIds.length > 0) {
            console.log(`[ShopRenter] Deleting ${excludedProductIds.length} excluded products from Qdrant...`)
            try {
              const { deletePointsByFilter, getCollectionName } = await import('../_shared/qdrant-client.ts')
              const collectionName = getCollectionName(store.store_name, 'products')
              await deletePointsByFilter(
                collectionName,
                {
                  key: 'product_id',
                  match: { any: excludedProductIds }
                }
              )
              console.log(`[ShopRenter] Deleted excluded products from Qdrant successfully`)
            } catch (qdrantDeleteError) {
              console.error('[ShopRenter] Error deleting excluded products from Qdrant:', qdrantDeleteError)
            }
          }

          // Sync remaining (non-excluded) products to Qdrant
          const qdrantResult = await syncProductsToQdrant(storeId, store.store_name, productsForQdrant, supabaseAdmin)
          console.log(`[ShopRenter] Qdrant sync complete: ${qdrantResult.synced} synced, ${qdrantResult.errors} errors, ${excludedProductIds.length} excluded`)
        }
      }
    } catch (error) {
      console.error('[ShopRenter] Product sync error:', error)
      productSyncError = error as Error
      syncStats.products.errors++
    }

    // Sync Orders to Qdrant (if enabled)
    // Note: Not cached to database for GDPR compliance, only synced to Qdrant for AI access
    const allOrders: any[] = []
    let orderSyncError: Error | null = null
    if (qdrantEnabled && canSyncOrders) {
      try {
        console.log('[ShopRenter] Syncing orders to Qdrant...')
        let page = 0
        let hasMore = true
        const limit = 50

        while (hasMore) {
          const ordersData = await fetchOrders(storeId, page, limit)

          if (ordersData.items && ordersData.items.length > 0) {
            allOrders.push(...ordersData.items)

            // Check if there are more pages
            if (ordersData.pagination && ordersData.pagination.total) {
              const totalPages = Math.ceil(ordersData.pagination.total / limit)
              hasMore = page < totalPages - 1
            } else {
              hasMore = ordersData.items.length === limit
            }

            page++
          } else {
            hasMore = false
          }
        }

        if (allOrders.length > 0) {
          const qdrantResult = await syncOrdersToQdrant(storeId, store.store_name, allOrders, supabaseAdmin)
          syncStats.orders.synced = qdrantResult.synced
          syncStats.orders.errors = qdrantResult.errors
          console.log(`[ShopRenter] Orders synced to Qdrant: ${qdrantResult.synced} synced, ${qdrantResult.errors} errors`)
        }
      } catch (error) {
        console.error('[ShopRenter] Order sync error:', error)
        orderSyncError = error as Error
        syncStats.orders.errors++
      }
    } else {
      console.log('[ShopRenter] Order sync skipped:', {
        qdrantEnabled,
        canSyncOrders
      })
    }

    // Sync Customers to Qdrant (if enabled)
    // Note: Not cached to database for GDPR compliance, only synced to Qdrant for AI access
    const allCustomers: any[] = []
    let customerSyncError: Error | null = null
    if (qdrantEnabled && canSyncCustomers) {
      try {
        console.log('[ShopRenter] Syncing customers to Qdrant...')
        let page = 0
        let hasMore = true
        const limit = 50

        while (hasMore) {
          const customersData = await fetchCustomers(storeId, page, limit)

          if (customersData.items && customersData.items.length > 0) {
            allCustomers.push(...customersData.items)

            // Check if there are more pages
            if (customersData.pagination && customersData.pagination.total) {
              const totalPages = Math.ceil(customersData.pagination.total / limit)
              hasMore = page < totalPages - 1
            } else {
              hasMore = customersData.items.length === limit
            }

            page++
          } else {
            hasMore = false
          }
        }

        if (allCustomers.length > 0) {
          const qdrantResult = await syncCustomersToQdrant(storeId, store.store_name, allCustomers, supabaseAdmin)
          syncStats.customers.synced = qdrantResult.synced
          syncStats.customers.errors = qdrantResult.errors
          console.log(`[ShopRenter] Customers synced to Qdrant: ${qdrantResult.synced} synced, ${qdrantResult.errors} errors`)
        }
      } catch (error) {
        console.error('[ShopRenter] Customer sync error:', error)
        customerSyncError = error as Error
        syncStats.customers.errors++
      }
    } else {
      console.log('[ShopRenter] Customer sync skipped:', {
        qdrantEnabled,
        canSyncCustomers
      })
    }

    // Update BOTH stores table and store_sync_config to maintain consistency
    const syncCompletedAt = new Date().toISOString()

    // Check if any critical errors occurred
    const hasErrors = productSyncError !== null || orderSyncError !== null || customerSyncError !== null
    const totalErrors = syncStats.products.errors + syncStats.orders.errors + syncStats.customers.errors
    const totalSynced = syncStats.products.synced + syncStats.orders.synced + syncStats.customers.synced

    // Build error message if any errors occurred
    let errorMessage: string | null = null
    const errorParts: string[] = []
    if (productSyncError) {
      errorParts.push(`Products: ${productSyncError.message}`)
    }
    if (orderSyncError) {
      errorParts.push(`Orders: ${orderSyncError.message}`)
    }
    if (customerSyncError) {
      errorParts.push(`Customers: ${customerSyncError.message}`)
    }
    if (errorParts.length > 0) {
      errorMessage = errorParts.join('; ')
    }

    // Update stores table (for Web UI display)
    await supabaseAdmin
      .from('stores')
      .update({
        alt_data: {
          last_sync_at: syncCompletedAt,
          last_sync_stats: syncStats,
          last_sync_type: 'manual'
        },
        sync_status: hasErrors ? 'error' : 'completed',
        sync_error: errorMessage
      })
      .eq('id', storeId)

    // Update store_sync_config (single source of truth for sync timing)
    const { error: configUpdateError } = await supabaseAdmin
      .from('store_sync_config')
      .update({
        last_sync_at: syncCompletedAt
      })
      .eq('store_id', storeId)

    // If config doesn't exist, create it
    if (configUpdateError) {
      await supabaseAdmin
        .from('store_sync_config')
        .insert({
          store_id: storeId,
          enabled: true,
          sync_frequency: 'hourly',
          last_sync_at: syncCompletedAt
        })
    }

    // Return error response if sync failed
    if (hasErrors && totalSynced === 0) {
      return new Response(
        JSON.stringify({
          success: false,
          error: 'Sync failed',
          message: errorMessage,
          stats: syncStats,
          timestamp: new Date().toISOString()
        }),
        { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
      )
    }

    // Return partial success if some items synced but there were errors
    if (hasErrors && totalSynced > 0) {
      return new Response(
        JSON.stringify({
          success: false,
          error: 'Sync completed with errors',
          message: errorMessage,
          stats: syncStats,
          timestamp: new Date().toISOString()
        }),
        { status: 207, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
      )
    }

    // Return success if no errors
    return new Response(
      JSON.stringify({
        success: true,
        message: 'Sync completed successfully',
        stats: syncStats,
        timestamp: new Date().toISOString()
      }),
      { status: 200, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
    )

  } catch (error: any) {
    console.error('[ShopRenter] Sync error:', error)
    return new Response(
      JSON.stringify({
        error: 'Sync failed',
        message: error.message
      }),
      { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
    )
  }
}))
