import { BaseService } from '@/core/base/BaseService'
import appConfig from '@/app.config'

export interface Merchant {
  id: string
  private_key: string
  public_key: string
  time?: number
  config: {
    name?: string
    about?: string
    picture?: string
    event_id?: string
    sync_from_nostr?: boolean
    active: boolean
    restore_in_progress?: boolean
  }
}

export interface Stall {
  id: string
  wallet: string
  name: string
  currency: string
  shipping_zones: Array<{
    id: string
    name: string
    cost: number
    countries: string[]
  }>
  config: {
    image_url?: string
    description?: string
  }
  pending: boolean
  event_id?: string
  event_created_at?: number
}

export interface CreateMerchantRequest {
  config: {
    name?: string
    about?: string
    picture?: string
    sync_from_nostr?: boolean
    active?: boolean
  }
}

export interface Zone {
  id: string
  name: string
  currency: string
  cost: number
  countries: string[]
}

export interface ProductShippingCost {
  id: string
  cost: number
}

export interface ProductConfig {
  description?: string
  currency?: string
  use_autoreply?: boolean
  autoreply_message?: string
  shipping: ProductShippingCost[]
}

export interface Product {
  id?: string
  stall_id: string
  name: string
  categories: string[]
  images: string[]
  price: number
  quantity: number
  active: boolean
  pending: boolean
  config: ProductConfig
  event_id?: string
  event_created_at?: number
}

export interface CreateProductRequest {
  stall_id: string
  name: string
  categories: string[]
  images: string[]
  price: number
  quantity: number
  active: boolean
  config: ProductConfig
}

export interface CreateZoneRequest {
  name: string
  currency: string
  cost: number
  countries: string[]
}

export interface CreateStallRequest {
  wallet: string
  name: string
  currency: string
  shipping_zones: Zone[]
  config: {
    image_url?: string
    description?: string
  }
}

export class NostrmarketAPI extends BaseService {
  // Service metadata
  protected readonly metadata = {
    name: 'NostrmarketAPI',
    version: '1.0.0',
    dependencies: [] // No dependencies - this is a market-specific service
  }

  private baseUrl: string

  constructor() {
    super()
    const config = appConfig.modules.market.config
    if (!config?.apiConfig?.baseUrl) {
      throw new Error('NostrmarketAPI: Missing apiConfig.baseUrl in market module config')
    }
    this.baseUrl = config.apiConfig.baseUrl
  }

  /**
   * Service-specific initialization (called by BaseService)
   */
  protected async onInitialize(): Promise<void> {
    this.debug('NostrmarketAPI initialized with base URL:', this.baseUrl)
    // Service is ready to use
  }

  private async request<T>(
    endpoint: string,
    walletKey: string,
    options: RequestInit = {}
  ): Promise<T> {
    const url = `${this.baseUrl}/nostrmarket${endpoint}`

    const headers: Record<string, string> = {
      'Content-Type': 'application/json',
      'X-API-KEY': walletKey,
    }

    // Merge with any additional headers
    if (options.headers) {
      Object.assign(headers, options.headers)
    }

    this.debug('NostrmarketAPI request:', {
      endpoint,
      fullUrl: url,
      method: options.method || 'GET',
      headers: {
        'Content-Type': headers['Content-Type'],
        'X-API-KEY': walletKey.substring(0, 8) + '...' + walletKey.substring(walletKey.length - 4)
      },
      bodyPreview: options.body ? JSON.stringify(JSON.parse(options.body as string), null, 2) : undefined
    })

    const response = await fetch(url, {
      ...options,
      headers,
    })

    if (!response.ok) {
      const errorText = await response.text()
      this.debug('NostrmarketAPI Error:', {
        status: response.status,
        statusText: response.statusText,
        errorText
      })

      // If 404, it means no merchant profile exists
      if (response.status === 404) {
        return null as T
      }

      // If 403, likely the nostrmarket extension is not enabled for this user
      if (response.status === 403) {
        throw new Error(`Access denied: Please ensure the NostrMarket extension is enabled for your LNbits account. Contact your administrator if needed.`)
      }

      throw new Error(`NostrmarketAPI request failed: ${response.status} ${response.statusText}`)
    }

    const data = await response.json()
    return data
  }

  /**
   * Get merchant profile for the current user
   * Uses wallet invoice key (inkey) as per the API specification
   */
  async getMerchant(walletInkey: string): Promise<Merchant | null> {
    try {
      const merchant = await this.request<Merchant>(
        '/api/v1/merchant',
        walletInkey,
        { method: 'GET' }
      )

      this.debug('Retrieved merchant:', {
        exists: !!merchant,
        merchantId: merchant?.id,
        active: merchant?.config?.active
      })

      return merchant
    } catch (error) {
      this.debug('Failed to get merchant:', error)
      // Return null instead of throwing - no merchant profile exists
      return null
    }
  }

  /**
   * Create a new merchant profile
   * Uses wallet admin key as per the API specification
   */
  async createMerchant(
    walletAdminkey: string,
    merchantData: CreateMerchantRequest
  ): Promise<Merchant> {
    const merchant = await this.request<Merchant>(
      '/api/v1/merchant',
      walletAdminkey,
      {
        method: 'POST',
        body: JSON.stringify(merchantData),
      }
    )

    this.debug('Created merchant:', { merchantId: merchant.id })

    return merchant
  }

  /**
   * Get stalls for the current merchant
   */
  async getStalls(walletInkey: string): Promise<Stall[]> {
    try {
      const stalls = await this.request<Stall[]>(
        '/api/v1/stall',
        walletInkey,
        { method: 'GET' }
      )

      this.debug('Retrieved stalls:', { count: stalls?.length || 0 })

      return stalls || []
    } catch (error) {
      this.debug('Failed to get stalls:', error)
      return []
    }
  }

  /**
   * Create a new stall
   */
  async createStall(
    walletAdminkey: string,
    stallData: CreateStallRequest
  ): Promise<Stall> {
    const stall = await this.request<Stall>(
      '/api/v1/stall',
      walletAdminkey,
      {
        method: 'POST',
        body: JSON.stringify(stallData),
      }
    )

    this.debug('Created stall:', { stallId: stall.id })

    return stall
  }

  /**
   * Get available shipping zones
   */
  async getZones(walletInkey: string): Promise<Zone[]> {
    try {
      const zones = await this.request<Zone[]>(
        '/api/v1/zone',
        walletInkey,
        { method: 'GET' }
      )

      this.debug('Retrieved zones:', { count: zones?.length || 0 })

      return zones || []
    } catch (error) {
      this.debug('Failed to get zones:', error)
      return []
    }
  }

  /**
   * Create a new shipping zone
   */
  async createZone(
    walletAdminkey: string,
    zoneData: CreateZoneRequest
  ): Promise<Zone> {
    const zone = await this.request<Zone>(
      '/api/v1/zone',
      walletAdminkey,
      {
        method: 'POST',
        body: JSON.stringify(zoneData),
      }
    )

    this.debug('Created zone:', { zoneId: zone.id, zoneName: zone.name })

    return zone
  }

  /**
   * Get available currencies
   */
  async getCurrencies(): Promise<string[]> {
    const baseCurrencies = ['sat']

    try {
      const apiCurrencies = await this.request<string[]>(
        '/api/v1/currencies',
        '', // No authentication needed for currencies endpoint
        { method: 'GET' }
      )

      if (apiCurrencies && Array.isArray(apiCurrencies)) {
        // Combine base currencies with API currencies, removing duplicates
        const allCurrencies = [...baseCurrencies, ...apiCurrencies.filter(currency => !baseCurrencies.includes(currency))]
        this.debug('Retrieved currencies:', { count: allCurrencies.length, currencies: allCurrencies })
        return allCurrencies
      }

      this.debug('No API currencies returned, using base currencies only')
      return baseCurrencies
    } catch (error) {
      this.debug('Failed to get currencies, falling back to base currencies:', error)
      return baseCurrencies
    }
  }

  /**
   * Get products for a stall
   */
  async getProducts(walletInkey: string, stallId: string, pending: boolean = false): Promise<Product[]> {
    const products = await this.request<Product[]>(
      `/api/v1/stall/product/${stallId}?pending=${pending}`,
      walletInkey,
      { method: 'GET' }
    )

    this.debug('Retrieved products:', {
      stallId,
      count: products?.length || 0,
      pending
    })

    return products || []
  }

  /**
   * Create a new product
   */
  async createProduct(
    walletAdminkey: string,
    productData: CreateProductRequest
  ): Promise<Product> {
    const product = await this.request<Product>(
      '/api/v1/product',
      walletAdminkey,
      {
        method: 'POST',
        body: JSON.stringify(productData),
      }
    )

    this.debug('Created product:', {
      productId: product.id,
      productName: product.name,
      stallId: product.stall_id
    })

    return product
  }

  /**
   * Update an existing product
   */
  async updateProduct(
    walletAdminkey: string,
    productId: string,
    productData: Product
  ): Promise<Product> {
    const product = await this.request<Product>(
      `/api/v1/product/${productId}`,
      walletAdminkey,
      {
        method: 'PATCH',
        body: JSON.stringify(productData),
      }
    )

    this.debug('Updated product:', {
      productId: product.id,
      productName: product.name
    })

    return product
  }

  /**
   * Get a single product by ID
   */
  async getProduct(walletInkey: string, productId: string): Promise<Product | null> {
    try {
      const product = await this.request<Product>(
        `/api/v1/product/${productId}`,
        walletInkey,
        { method: 'GET' }
      )

      this.debug('Retrieved product:', {
        productId: product?.id,
        productName: product?.name
      })

      return product
    } catch (error) {
      this.debug('Failed to get product:', error)
      return null
    }
  }

  /**
   * Delete a product
   */
  async deleteProduct(walletAdminkey: string, productId: string): Promise<void> {
    await this.request<void>(
      `/api/v1/product/${productId}`,
      walletAdminkey,
      { method: 'DELETE' }
    )

    this.debug('Deleted product:', { productId })
  }
}
