import { useCallback, useMemo, useState } from "react"
import { api } from "@/lib/api"
import { ENDPOINTS } from "@/constants/endpoints"
import { createEntityHook } from "./useEntityBase"
import type {
  ApiResponse,
  BuyOrderCreatePayload,
  BuyOrderRead,
  BuyOrderUpdatePayload,
  CombinedOrderRead,
  OrderPostingResult,
  OrderWorkflowAction,
  SellOrderCreatePayload,
  SellOrderRead,
  SellOrderUpdatePayload,
} from "@/types"

function unwrap<T>(response: unknown, fallback: T): T {
  const value = response as ApiResponse<T> | T
  if (value && typeof value === "object" && "data" in value) {
    return ((value as ApiResponse<T>).data ?? fallback) as T
  }
  return (response ?? fallback) as T
}

function asString(value: unknown, fallback = "0") {
  return value === null || value === undefined ? fallback : String(value)
}

function sumOrderWeight(items: Array<{ weight_grams: string; quantity: number }>) {
  const total = items.reduce((sum, item) => {
    return sum + (Number(item.weight_grams) || 0) * (Number(item.quantity) || 1)
  }, 0)
  return total ? String(total) : null
}

function firstPrice(items: Array<{ price_per_gram: string }>) {
  return items[0]?.price_per_gram ? String(items[0].price_per_gram) : null
}

function mapBuyOrder(order: BuyOrderRead): CombinedOrderRead {
  return {
    id: order.id,
    order_no: order.buy_order_no,
    order_type: "buy",
    workflow_type: order.buy_order_type,
    status: order.status,
    priority: order.priority,
    user_id: order.user_id,
    customer_id: order.customer_id,
    customer_name: null,
    branch_id: order.target_branch_id,
    vault_id: order.target_vault_id,
    currency_id: order.currency_id,
    requested_grams: sumOrderWeight(order.items ?? []),
    price_per_gram: firstPrice(order.items ?? []),
    subtotal_amount: asString(order.subtotal_amount),
    fee_amount: asString(order.fee_amount),
    tax_amount: asString(order.tax_amount),
    discount_amount: asString(order.discount_amount),
    total_amount: asString(order.total_amount),
    notes: order.notes,
    reviewed_at: order.reviewed_at,
    approved_at: order.approved_at,
    posted_at: order.posted_at,
    rejected_at: order.rejected_at,
    cancelled_at: order.cancelled_at,
    cancellation_reason: order.cancellation_reason,
    created_at: order.created_at,
    updated_at: order.updated_at,
  }
}

function mapSellOrder(order: SellOrderRead): CombinedOrderRead {
  return {
    id: order.id,
    order_no: order.sell_order_no,
    order_type: "sell",
    workflow_type: order.sell_order_type,
    status: order.status,
    priority: order.priority,
    user_id: order.user_id,
    customer_id: order.customer_id,
    customer_name: null,
    branch_id: order.branch_id,
    vault_id: order.vault_id,
    currency_id: order.currency_id,
    requested_grams: sumOrderWeight(order.items ?? []),
    price_per_gram: firstPrice(order.items ?? []),
    subtotal_amount: asString(order.subtotal_amount),
    fee_amount: asString(order.fee_amount),
    tax_amount: asString(order.tax_amount),
    discount_amount: asString(order.discount_amount),
    total_amount: asString(order.total_amount),
    notes: order.notes,
    price_snapshot: order.price_snapshot,
    expires_at: order.expires_at,
    reviewed_at: order.reviewed_at,
    approved_at: order.approved_at,
    posted_at: order.posted_at,
    rejected_at: order.rejected_at,
    cancelled_at: order.cancelled_at,
    cancellation_reason: order.cancellation_reason,
    created_at: order.created_at,
    updated_at: order.updated_at,
  }
}

function actionEndpoint(order: CombinedOrderRead, action: OrderWorkflowAction) {
  const endpoints = order.order_type === "buy" ? ENDPOINTS.BUY_ORDERS : ENDPOINTS.SELL_ORDERS

  switch (action) {
    case "submit-for-review":
      return endpoints.SUBMIT_FOR_REVIEW(order.id)
    case "submit-for-approval":
      return endpoints.SUBMIT_FOR_APPROVAL(order.id)
    case "approve":
      return endpoints.APPROVE(order.id)
    case "reject":
      return endpoints.REJECT(order.id)
    case "cancel":
      return endpoints.CANCEL(order.id)
    case "post":
      return order.order_type === "buy" ? ENDPOINTS.BUY_ORDERS.POST_APPROVAL(order.id) : ENDPOINTS.SELL_ORDERS.POST(order.id)
  }
}

export const useBuyOrdersBase = createEntityHook<BuyOrderRead, BuyOrderCreatePayload, BuyOrderUpdatePayload>(
  "Buy orders",
  ENDPOINTS.BUY_ORDERS.LIST,
)

export const useSellOrdersBase = createEntityHook<SellOrderRead, SellOrderCreatePayload, SellOrderUpdatePayload>(
  "Sell orders",
  ENDPOINTS.SELL_ORDERS.LIST,
)

export function useOrders() {
  const buyOrdersBase = useBuyOrdersBase()
  const sellOrdersBase = useSellOrdersBase()
  const [isSubmitting, setIsSubmitting] = useState(false)
  const [searchTerm, setSearchTerm] = useState("")
  const [postingResult, setPostingResult] = useState<OrderPostingResult | null>(null)
  const [actionError, setActionError] = useState<string | null>(null)
  const [orderDetails, setOrderDetails] = useState<{
    postings: OrderPostingResult | null
    auditLogs: any[]
    isLoading: boolean
  }>({ postings: null, auditLogs: [], isLoading: false })

  const items = useMemo(() => {
    const term = searchTerm.trim().toLowerCase()
    return [
      ...buyOrdersBase.items.map(mapBuyOrder),
      ...sellOrdersBase.items.map(mapSellOrder),
    ]
      .filter((order) => {
        if (!term) return true
        return (
          order.order_no.toLowerCase().includes(term) ||
          order.status.toLowerCase().includes(term) ||
          order.workflow_type.toLowerCase().includes(term) ||
          order.customer_id?.toLowerCase().includes(term)
        )
      })
      .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())
  }, [buyOrdersBase.items, searchTerm, sellOrdersBase.items])

  const totalCount = items.length

  const fetchItems = useCallback(async (_page = 1, size = 100, search = "") => {
    setSearchTerm(search)
    await Promise.all([
      buyOrdersBase.fetchItems(1, size, ""),
      sellOrdersBase.fetchItems(1, size, ""),
    ])
  }, [buyOrdersBase.fetchItems, sellOrdersBase.fetchItems])

  const transitionOrder = useCallback(async (
    order: CombinedOrderRead,
    action: OrderWorkflowAction,
    note?: string,
  ) => {
    setIsSubmitting(true)
    setActionError(null)
    setPostingResult(null)
    try {
      const body = action === "cancel" ? { reason: note } : action === "post" ? undefined : { note: note || null }
      const response = await api.post(actionEndpoint(order, action), body)
      if (action === "post") {
        setPostingResult(unwrap<OrderPostingResult | null>(response, null))
      }
      await fetchItems(1, 100, searchTerm)
      return true
    } catch (err) {
      const message = err instanceof Error ? err.message : `Failed to ${action.replace(/-/g, " ")} order.`
      setActionError(message)
      return false
    } finally {
      setIsSubmitting(false)
    }
  }, [fetchItems, searchTerm])

  const fetchOrderDetails = useCallback(async (orderId: string, orderType: "buy" | "sell") => {
    setOrderDetails(prev => ({ ...prev, isLoading: true }))
    try {
      const endpoints = orderType === "buy" ? ENDPOINTS.BUY_ORDERS : ENDPOINTS.SELL_ORDERS
      
      const [postingsRes, logsRes] = await Promise.allSettled([
        api.get(endpoints.POSTINGS(orderId)),
        api.get(`${ENDPOINTS.AUDIT_LOGS.LIST}?entity_id=${orderId}`)
      ])

      setOrderDetails({
        postings: postingsRes.status === "fulfilled" ? unwrap<OrderPostingResult | null>(postingsRes.value, null) : null,
        auditLogs: logsRes.status === "fulfilled" ? unwrap<{items: any[]}>(logsRes.value, { items: [] }).items : [],
        isLoading: false
      })
    } catch (err) {
      setOrderDetails(prev => ({ ...prev, isLoading: false }))
    }
  }, [])

  return useMemo(() => ({
    items,
    totalCount,
    fetchItems,
    isLoading: buyOrdersBase.isLoading || sellOrdersBase.isLoading,
    isSubmitting,
    error: actionError || buyOrdersBase.error || sellOrdersBase.error,
    postingResult,
    transitionOrder,
    buyOrdersBase,
    sellOrdersBase,
    orderDetails,
    fetchOrderDetails,
  }), [actionError, buyOrdersBase, fetchItems, isSubmitting, items, postingResult, sellOrdersBase, totalCount, transitionOrder, orderDetails, fetchOrderDetails])
}
