import { getDb } from '../db'
import { Context } from '../types/context'
import { GraphQLError } from 'graphql'
import { logger } from '../lib/logger'
import crypto from 'crypto'

export interface APIMarketplaceListing {
  id: string
  name: string
  description: string
  provider: string
  endpoint: string
  documentationUrl: string | null
  category: string
  pricing: {
    model: string
    basePrice: number | null
    perRequestPrice: number | null
    freeTier: {
      requestsPerMonth: number
      features: string[]
    } | null
  }
  rating: number
  reviewCount: number
  requestCount: number
  status: string
  createdAt: Date
  updatedAt: Date
}

export interface APISubscription {
  id: string
  listingId: string
  userId: string
  status: string
  apiKey: string | null
  createdAt: Date
  updatedAt: Date
}

export async function getAPIMarketplaceListings(filter?: {
  category?: string
  search?: string
  status?: string
  limit?: number
  offset?: number
}): Promise<APIMarketplaceListing[]> {
  const db = getDb()
  const conditions: string[] = []
  const params: any[] = []
  let paramIndex = 1

  if (filter?.category) {
    conditions.push(`category = $${paramIndex++}`)
    params.push(filter.category)
  }

  if (filter?.search) {
    conditions.push(`(name ILIKE $${paramIndex} OR description ILIKE $${paramIndex})`)
    params.push(`%${filter.search}%`)
    paramIndex++
  }

  if (filter?.status) {
    conditions.push(`status = $${paramIndex++}`)
    params.push(filter.status)
  }

  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''
  const limit = filter?.limit || 50
  const offset = filter?.offset || 0

  const result = await db.query(`
    SELECT 
      l.*,
      COALESCE(AVG(r.rating), 0) as rating,
      COUNT(DISTINCT r.id) as review_count,
      COUNT(DISTINCT s.id) as request_count
    FROM api_marketplace_listings l
    LEFT JOIN api_marketplace_reviews r ON r.listing_id = l.id
    LEFT JOIN api_subscriptions s ON s.listing_id = l.id
    ${whereClause}
    GROUP BY l.id
    ORDER BY l.created_at DESC
    LIMIT $${paramIndex++} OFFSET $${paramIndex++}
  `, [...params, limit, offset])

  return result.rows.map(row => ({
    id: row.id,
    name: row.name,
    description: row.description,
    provider: row.provider,
    endpoint: row.endpoint,
    documentationUrl: row.documentation_url,
    category: row.category,
    pricing: {
      model: row.pricing_model,
      basePrice: row.base_price,
      perRequestPrice: row.per_request_price,
      freeTier: row.free_tier ? JSON.parse(row.free_tier) : null,
    },
    rating: parseFloat(row.rating) || 0,
    reviewCount: parseInt(row.review_count) || 0,
    requestCount: parseInt(row.request_count) || 0,
    status: row.status,
    createdAt: new Date(row.created_at),
    updatedAt: new Date(row.updated_at),
  }))
}

export async function getAPIMarketplaceListing(id: string): Promise<APIMarketplaceListing | null> {
  const db = getDb()
  const result = await db.query(`
    SELECT 
      l.*,
      COALESCE(AVG(r.rating), 0) as rating,
      COUNT(DISTINCT r.id) as review_count,
      COUNT(DISTINCT s.id) as request_count
    FROM api_marketplace_listings l
    LEFT JOIN api_marketplace_reviews r ON r.listing_id = l.id
    LEFT JOIN api_subscriptions s ON s.listing_id = l.id
    WHERE l.id = $1
    GROUP BY l.id
  `, [id])

  if (result.rows.length === 0) {
    return null
  }

  const row = result.rows[0]
  return {
    id: row.id,
    name: row.name,
    description: row.description,
    provider: row.provider,
    endpoint: row.endpoint,
    documentationUrl: row.documentation_url,
    category: row.category,
    pricing: {
      model: row.pricing_model,
      basePrice: row.base_price,
      perRequestPrice: row.per_request_price,
      freeTier: row.free_tier ? JSON.parse(row.free_tier) : null,
    },
    rating: parseFloat(row.rating) || 0,
    reviewCount: parseInt(row.review_count) || 0,
    requestCount: parseInt(row.request_count) || 0,
    status: row.status,
    createdAt: new Date(row.created_at),
    updatedAt: new Date(row.updated_at),
  }
}

export async function getMyAPISubscriptions(context: Context): Promise<APISubscription[]> {
  if (!context.user) {
    throw new GraphQLError('Authentication required', {
      extensions: { code: 'UNAUTHENTICATED' },
    })
  }

  const db = getDb()
  const result = await db.query(
    'SELECT * FROM api_subscriptions WHERE user_id = $1 ORDER BY created_at DESC',
    [context.user.id]
  )

  return result.rows.map(row => ({
    id: row.id,
    listingId: row.listing_id,
    userId: row.user_id,
    status: row.status,
    apiKey: row.api_key,
    createdAt: new Date(row.created_at),
    updatedAt: new Date(row.updated_at),
  }))
}

export async function createAPIMarketplaceListing(
  context: Context,
  input: {
    name: string
    description: string
    provider: string
    endpoint: string
    documentationUrl?: string
    category: string
    pricing: {
      model: string
      basePrice?: number
      perRequestPrice?: number
      freeTier?: {
        requestsPerMonth: number
        features: string[]
      }
    }
  }
): Promise<APIMarketplaceListing> {
  if (!context.user) {
    throw new GraphQLError('Authentication required', {
      extensions: { code: 'UNAUTHENTICATED' },
    })
  }

  const db = getDb()
  const result = await db.query(
    `INSERT INTO api_marketplace_listings 
     (name, description, provider, endpoint, documentation_url, category, pricing_model, base_price, per_request_price, free_tier, status, created_at, updated_at)
     VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, 'PENDING', NOW(), NOW())
     RETURNING *`,
    [
      input.name,
      input.description,
      input.provider,
      input.endpoint,
      input.documentationUrl || null,
      input.category,
      input.pricing.model,
      input.pricing.basePrice || null,
      input.pricing.perRequestPrice || null,
      input.pricing.freeTier ? JSON.stringify(input.pricing.freeTier) : null,
    ]
  )

  const row = result.rows[0]
  return {
    id: row.id,
    name: row.name,
    description: row.description,
    provider: row.provider,
    endpoint: row.endpoint,
    documentationUrl: row.documentation_url,
    category: row.category,
    pricing: {
      model: row.pricing_model,
      basePrice: row.base_price,
      perRequestPrice: row.per_request_price,
      freeTier: row.free_tier ? JSON.parse(row.free_tier) : null,
    },
    rating: 0,
    reviewCount: 0,
    requestCount: 0,
    status: row.status,
    createdAt: new Date(row.created_at),
    updatedAt: new Date(row.updated_at),
  }
}

export async function updateAPIMarketplaceListing(
  context: Context,
  id: string,
  input: {
    name?: string
    description?: string
    status?: string
    pricing?: {
      model: string
      basePrice?: number
      perRequestPrice?: number
      freeTier?: {
        requestsPerMonth: number
        features: string[]
      }
    }
  }
): Promise<APIMarketplaceListing> {
  if (!context.user) {
    throw new GraphQLError('Authentication required', {
      extensions: { code: 'UNAUTHENTICATED' },
    })
  }

  const db = getDb()
  const updates: string[] = []
  const params: any[] = []
  let paramIndex = 1

  if (input.name) {
    updates.push(`name = $${paramIndex++}`)
    params.push(input.name)
  }

  if (input.description) {
    updates.push(`description = $${paramIndex++}`)
    params.push(input.description)
  }

  if (input.status) {
    updates.push(`status = $${paramIndex++}`)
    params.push(input.status)
  }

  if (input.pricing) {
    updates.push(`pricing_model = $${paramIndex++}`)
    params.push(input.pricing.model)
    
    if (input.pricing.basePrice !== undefined) {
      updates.push(`base_price = $${paramIndex++}`)
      params.push(input.pricing.basePrice)
    }
    
    if (input.pricing.perRequestPrice !== undefined) {
      updates.push(`per_request_price = $${paramIndex++}`)
      params.push(input.pricing.perRequestPrice)
    }
    
    if (input.pricing.freeTier) {
      updates.push(`free_tier = $${paramIndex++}`)
      params.push(JSON.stringify(input.pricing.freeTier))
    }
  }

  updates.push(`updated_at = NOW()`)
  params.push(id)

  const result = await db.query(
    `UPDATE api_marketplace_listings SET ${updates.join(', ')} WHERE id = $${paramIndex} RETURNING *`,
    params
  )

  if (result.rows.length === 0) {
    throw new GraphQLError('Listing not found', {
      extensions: { code: 'NOT_FOUND' },
    })
  }

  const row = result.rows[0]
  const ratingResult = await db.query(
    'SELECT AVG(rating) as rating, COUNT(*) as count FROM api_marketplace_reviews WHERE listing_id = $1',
    [id]
  )

  return {
    id: row.id,
    name: row.name,
    description: row.description,
    provider: row.provider,
    endpoint: row.endpoint,
    documentationUrl: row.documentation_url,
    category: row.category,
    pricing: {
      model: row.pricing_model,
      basePrice: row.base_price,
      perRequestPrice: row.per_request_price,
      freeTier: row.free_tier ? JSON.parse(row.free_tier) : null,
    },
    rating: parseFloat(ratingResult.rows[0]?.rating) || 0,
    reviewCount: parseInt(ratingResult.rows[0]?.count) || 0,
    requestCount: 0,
    status: row.status,
    createdAt: new Date(row.created_at),
    updatedAt: new Date(row.updated_at),
  }
}

export async function deleteAPIMarketplaceListing(context: Context, id: string): Promise<boolean> {
  if (!context.user) {
    throw new GraphQLError('Authentication required', {
      extensions: { code: 'UNAUTHENTICATED' },
    })
  }

  const db = getDb()
  await db.query('DELETE FROM api_subscriptions WHERE listing_id = $1', [id])
  await db.query('DELETE FROM api_marketplace_reviews WHERE listing_id = $1', [id])
  await db.query('DELETE FROM api_marketplace_listings WHERE id = $1', [id])

  return true
}

export async function subscribeToAPI(context: Context, listingId: string): Promise<APISubscription> {
  if (!context.user) {
    throw new GraphQLError('Authentication required', {
      extensions: { code: 'UNAUTHENTICATED' },
    })
  }

  const db = getDb()
  
  // Check if already subscribed
  const existing = await db.query(
    'SELECT * FROM api_subscriptions WHERE user_id = $1 AND listing_id = $2',
    [context.user.id, listingId]
  )

  if (existing.rows.length > 0) {
    throw new GraphQLError('Already subscribed', {
      extensions: { code: 'VALIDATION_ERROR' },
    })
  }

  // Generate API key
  const apiKey = `sk_${crypto.randomBytes(32).toString('hex')}`

  const result = await db.query(
    `INSERT INTO api_subscriptions (listing_id, user_id, status, api_key, created_at, updated_at)
     VALUES ($1, $2, 'ACTIVE', $3, NOW(), NOW())
     RETURNING *`,
    [listingId, context.user.id, apiKey]
  )

  const row = result.rows[0]
  return {
    id: row.id,
    listingId: row.listing_id,
    userId: row.user_id,
    status: row.status,
    apiKey: row.api_key,
    createdAt: new Date(row.created_at),
    updatedAt: new Date(row.updated_at),
  }
}

export async function unsubscribeFromAPI(context: Context, subscriptionId: string): Promise<boolean> {
  if (!context.user) {
    throw new GraphQLError('Authentication required', {
      extensions: { code: 'UNAUTHENTICATED' },
    })
  }

  const db = getDb()
  
  // Check ownership
  const sub = await db.query(
    'SELECT user_id FROM api_subscriptions WHERE id = $1',
    [subscriptionId]
  )

  if (sub.rows.length === 0) {
    throw new GraphQLError('Subscription not found', {
      extensions: { code: 'NOT_FOUND' },
    })
  }

  if (sub.rows[0].user_id !== context.user.id) {
    throw new GraphQLError('Permission denied', {
      extensions: { code: 'FORBIDDEN' },
    })
  }

  await db.query(
    'UPDATE api_subscriptions SET status = $1, updated_at = NOW() WHERE id = $2',
    ['CANCELLED', subscriptionId]
  )

  return true
}

