/**
 * WooCommerce client
 * Handles all interactions with WooCommerce REST API
 */

import { z } from "zod"
import { createHmac, randomBytes } from "crypto"
import type { Address } from "./schemas"
import { env } from "./env"
import { calculatePricing } from "./pricing"

const WC_BASE_URL = env.WC_BASE_URL
const WC_CONSUMER_KEY = env.WC_CONSUMER_KEY
const WC_CONSUMER_SECRET = env.WC_CONSUMER_SECRET

// Zod schemas for runtime validation
const WooAddressSchema = z.object({
  first_name: z.string(),
  last_name: z.string(),
  address_1: z.string(),
  address_2: z.string(),
  city: z.string(),
  state: z.string(),
  postcode: z.string(),
  country: z.string(),
  email: z.string().optional(),
})

const WooLineItemSchema = z.object({
  id: z.number(),
  name: z.string(),
  product_id: z.number(),
  quantity: z.number(),
  subtotal: z.string(),
  total: z.string(),
  image: z.object({ src: z.string() }).optional(),
})

const WooShippingLineSchema = z.object({
  id: z.number(),
  method_title: z.string(),
  total: z.string(),
})

const WooMetaSchema = z.object({
  key: z.string(),
  value: z.union([z.string(), z.number()]),
})

const WooOrderSchema = z.object({
  id: z.number(),
  status: z.string(),
  total: z.string(),
  currency: z.string(),
  billing: WooAddressSchema,
  shipping: WooAddressSchema,
  line_items: z.array(WooLineItemSchema),
  shipping_lines: z.array(WooShippingLineSchema),
  shipping_total: z.string().optional(), // Direct shipping total field
  meta_data: z.array(WooMetaSchema),
  customer_note: z.string(),
  billing_email: z.string().optional(),
  customer_id: z.number(),
  created_via: z.string().optional(),
})

export interface WooOrder {
  id: number
  status: string
  total: string
  currency: string
  billing: WooAddress
  shipping: WooAddress
  line_items: WooLineItem[]
  shipping_lines: WooShippingLine[]
  shipping_total?: string // Direct shipping total field
  meta_data: WooMeta[]
  customer_note: string
  billing_email?: string
  customer_id: number
  created_via?: string
}

export interface WooAddress {
  first_name: string
  last_name: string
  address_1: string
  address_2: string
  city: string
  state: string
  postcode: string
  country: string
  email?: string
}

export interface WooLineItem {
  id: number
  name: string
  product_id: number
  quantity: number
  subtotal: string
  total: string
  image?: {
    src: string
  }
}

export interface WooShippingLine {
  id: number
  method_title: string
  total: string
}

export interface WooMeta {
  key: string
  value: string | number
}

export interface NormalizedOrder {
  id: number
  status: string
  /** Grand total = subtotal + shipping + tax, in cents */
  total_cents: number
  /** Product subtotal (sum of line items), in cents */
  subtotal_cents: number
  /** Tax amount, in cents */
  tax_cents: number
  currency: string
  email: string
  items: {
    name: string
    quantity: number
    price_cents: number
    image?: string
  }[]
  shipping_method?: string
  shipping_cost_cents: number
  /** Original shipping cost before free-shipping discount, in cents */
  original_shipping_cents: number
  payment_intent_id?: string
  nonce?: string
}

export class WooCommerce {
  /**
   * Check if using HTTPS (for Basic Auth) or HTTP (for OAuth 1.0)
   */
  private static isSecure(): boolean {
    return WC_BASE_URL.startsWith("https://")
  }

  /**
   * Generate OAuth 1.0 signature for WooCommerce API
   */
  private static generateOAuthSignature(method: string, url: string, params: Record<string, string>): string {
    // Sort parameters alphabetically
    const sortedParams = Object.keys(params)
      .sort()
      .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
      .join("&")

    // Create signature base string
    const baseString = [
      method.toUpperCase(),
      encodeURIComponent(url),
      encodeURIComponent(sortedParams),
    ].join("&")

    // Generate signature using HMAC-SHA256
    const signature = createHmac("sha256", `${WC_CONSUMER_SECRET}&`)
      .update(baseString)
      .digest("base64")

    return signature
  }

  /**
   * Build authenticated URL for WooCommerce API
   * Uses OAuth 1.0 for HTTP or Basic Auth for HTTPS
   */
  private static buildAuthUrl(endpoint: string, method: string = "GET"): string {
    const url = `${WC_BASE_URL}${endpoint}`

    if (this.isSecure()) {
      // HTTPS: Use Basic Auth via headers (handled in fetch)
      return url
    } else {
      // HTTP: Use OAuth 1.0 via query parameters
      const oauthParams: Record<string, string> = {
        oauth_consumer_key: WC_CONSUMER_KEY,
        oauth_timestamp: Math.floor(Date.now() / 1000).toString(),
        oauth_nonce: randomBytes(16).toString("hex"),
        oauth_signature_method: "HMAC-SHA256",
        oauth_version: "1.0",
      }

      // Generate signature
      const signature = this.generateOAuthSignature(method, url, oauthParams)
      oauthParams.oauth_signature = signature

      // Build URL with OAuth parameters
      const queryString = Object.keys(oauthParams)
        .map((key) => `${key}=${encodeURIComponent(oauthParams[key])}`)
        .join("&")

      return `${url}?${queryString}`
    }
  }

  /**
   * Get auth headers (only for HTTPS)
   */
  private static getAuthHeaders(): Record<string, string> {
    if (this.isSecure()) {
      const credentials = Buffer.from(`${WC_CONSUMER_KEY}:${WC_CONSUMER_SECRET}`).toString("base64")
      return {
        Authorization: `Basic ${credentials}`,
        "Content-Type": "application/json",
      }
    }
    return {
      "Content-Type": "application/json",
    }
  }

  /**
   * Fetch order from WooCommerce
   */
  static async getOrder(orderId: number): Promise<WooOrder> {
    const url = this.buildAuthUrl(`/wp-json/wc/v3/orders/${orderId}`, "GET")
    
    const response = await fetch(url, {
      headers: this.getAuthHeaders(),
    })

    if (!response.ok) {
      throw new Error(`Failed to fetch order: ${response.statusText}`)
    }

    const data = await response.json()
    
    // Validate response structure
    try {
      return WooOrderSchema.parse(data)
    } catch (error) {
      throw new Error(`Invalid WooCommerce order response: ${error instanceof Error ? error.message : "Unknown error"}`)
    }
  }

  /**
   * Update order in WooCommerce
   */
  static async updateOrder(orderId: number, data: Partial<WooOrder>): Promise<WooOrder> {
    const url = this.buildAuthUrl(`/wp-json/wc/v3/orders/${orderId}`, "PUT")
    
    const response = await fetch(url, {
      method: "PUT",
      headers: this.getAuthHeaders(),
      body: JSON.stringify(data),
    })

    if (!response.ok) {
      throw new Error(`Failed to update order: ${response.statusText}`)
    }

    return response.json()
  }

  /**
   * Get meta value from order
   */
  static getMeta(order: WooOrder, key: string): string | number | undefined {
    const meta = order.meta_data.find((m) => m.key === key)
    return meta?.value
  }

  /**
   * Set meta value on order
   */
  static setMeta(order: WooOrder, key: string, value: string | number): WooMeta[] {
    const metaData = [...order.meta_data]
    const existingIndex = metaData.findIndex((m) => m.key === key)

    if (existingIndex >= 0) {
      metaData[existingIndex].value = value
    } else {
      metaData.push({ key, value })
    }

    return metaData
  }

  /**
   * Normalize WooCommerce order for frontend
   */
  static normalize(order: WooOrder): NormalizedOrder {
    // Get raw shipping cost from shipping_lines first
    let rawShippingCents = order.shipping_lines.reduce(
      (sum, line) => sum + Math.round(Number.parseFloat(line.total) * 100),
      0,
    )

    // Fallback to shipping_total if shipping_lines is empty
    if (rawShippingCents === 0 && order.shipping_total) {
      rawShippingCents = Math.round(Number.parseFloat(order.shipping_total) * 100)
    }

    // Get per-item totals in cents
    const itemTotalsCents = order.line_items.map(
      (item) => Math.round(Number.parseFloat(item.total) * 100)
    )

    // Calculate full pricing breakdown (subtotal + tax + shipping)
    const pricing = calculatePricing(itemTotalsCents, rawShippingCents)

    return {
      id: order.id,
      status: order.status,
      total_cents: pricing.total_cents,
      subtotal_cents: pricing.subtotal_cents,
      tax_cents: pricing.tax_cents,
      currency: order.currency,
      email: order.billing.email || order.billing_email || "",
      items: order.line_items.map((item) => ({
        name: item.name,
        quantity: item.quantity,
        price_cents: Math.round(Number.parseFloat(item.total) * 100),
        image: item.image?.src,
      })),
      shipping_method: order.shipping_lines[0]?.method_title,
      shipping_cost_cents: pricing.shipping_cents,
      original_shipping_cents: pricing.original_shipping_cents,
      payment_intent_id: this.getMeta(order, "_payment_intent_id") as string | undefined,
      nonce: this.getMeta(order, "_checkout_nonce") as string | undefined,
    }
  }

  /**
   * Check if order can be paid
   * Status lifecycle: pending → processing → shipped → completed
   */
  static canBePaid(order: WooOrder): boolean {
    return order.status === "pending"
  }

  /**
   * Check if order is already paid
   * Includes: processing, shipped, completed, on-hold
   */
  static isPaid(order: WooOrder): boolean {
    return ["processing", "shipped", "completed", "on-hold"].includes(order.status)
  }

  /**
   * Check if order has been shipped
   */
  static isShipped(order: WooOrder): boolean {
    return ["shipped", "completed"].includes(order.status)
  }

  /**
   * Restore cart items from a pending order
   * This recreates cart items from the order line items
   */
  static async restoreCartFromOrder(order: WooOrder): Promise<boolean> {
    try {
      console.log(`[v0] Attempting to restore cart from order ${order.id}`)
      
      // For logged-in customers, we can restore via customer endpoint
      if (order.customer_id > 0) {
        // Build cart data from order line items
        const cartItems: any = {}
        
        order.line_items.forEach((item, index) => {
          cartItems[index] = {
            product_id: item.product_id,
            quantity: item.quantity,
          }
        })

        // Store cart in customer meta
        const url = this.buildAuthUrl(`/wp-json/wc/v3/customers/${order.customer_id}`, "PUT")
        
        const response = await fetch(url, {
          method: "PUT",
          headers: this.getAuthHeaders(),
          body: JSON.stringify({
            meta_data: [
              {
                key: `_woocommerce_persistent_cart_${order.customer_id}`,
                value: JSON.stringify({ cart: cartItems }),
              },
            ],
          }),
        })

        if (response.ok) {
          console.log(`[v0] Cart restored successfully for customer ${order.customer_id}`)
          return true
        } else {
          console.warn(`[v0] Failed to restore cart via API:`, await response.text())
        }
      }
      
      // For guest customers, cart restoration requires session handling
      // This would need to be done on the WooCommerce side
      console.warn(`[v0] Cannot restore cart for guest customer (order ${order.id})`)
      return false
      
    } catch (error) {
      console.error(`[v0] Error restoring cart:`, error)
      return false
    }
  }

  /**
   * Cancel order and restore cart
   * Use this when payment is abandoned or fails
   */
  static async cancelAndRestoreCart(orderId: number): Promise<void> {
    try {
      const order = await this.getOrder(orderId)
      
      // Only cancel if still pending
      if (order.status !== "pending") {
        console.log(`[v0] Order ${orderId} is not pending, skipping cancellation`)
        return
      }

      // Attempt to restore cart first
      const restored = await this.restoreCartFromOrder(order)
      
      // Update order to cancelled status
      await this.updateOrder(orderId, {
        status: "cancelled",
        customer_note: restored 
          ? "Payment was not completed. Your cart has been restored." 
          : "Payment was not completed. Please return to your cart to reorder.",
        meta_data: [
          ...order.meta_data,
          {
            key: "_cart_restored",
            value: restored ? "yes" : "no",
          },
          {
            key: "_cancelled_at",
            value: new Date().toISOString(),
          },
        ],
      })
      
      console.log(`[v0] Order ${orderId} cancelled, cart restored: ${restored}`)
    } catch (error) {
      console.error(`[v0] Failed to cancel order ${orderId}:`, error)
    }
  }

  /**
   * Clear customer cart after successful payment
   * This is called after payment is confirmed
   */
  static async clearCart(customerId: number): Promise<void> {
    if (customerId === 0) {
      // Guest checkout - cart is already cleared when order was created
      return
    }

    // For logged-in customers, clear the cart via REST API
    // Note: This may require a custom endpoint in WooCommerce
    // Standard WooCommerce doesn't expose cart clearing via REST API
    const url = this.buildAuthUrl(`/wp-json/wc/v3/customers/${customerId}`, "PUT")
    
    try {
      await fetch(url, {
        method: "PUT",
        headers: this.getAuthHeaders(),
        body: JSON.stringify({
          meta_data: [
            {
              key: "_woocommerce_persistent_cart_" + customerId,
              value: "",
            },
          ],
        }),
      })
    } catch (error) {
      // Cart clearing is not critical - WooCommerce will handle it
      console.warn(`[v0] Could not clear cart for customer ${customerId}:`, error)
    }
  }

  /**
   * Convert Address schema to WooCommerce address format
   */
  static toWooAddress(address: Address): WooAddress {
    return {
      first_name: address.first_name,
      last_name: address.last_name,
      address_1: address.address_1,
      address_2: address.address_2 || "",
      city: address.city,
      state: address.state,
      postcode: address.postcode,
      country: address.country,
    }
  }
}
