import { useCallback, useState } from "react"
import axios from "axios"
import { api } from "@/lib/api"
import { ENDPOINTS } from "@/constants/endpoints"
import type {
  ApprovalRequest,
  BuyOrderCreateRequest,
  BuyOrderDetail,
  BuyOrderFilters,
  BuyOrderItem,
  BuyOrderItemPayload,
  BuyOrderListItem,
  BuyOrderPostingResult,
  BuyOrderSupportData,
  BuyOrderVoucher,
  BuyPrice,
  PaginatedResponse,
  StatusHistory,
} from "@/types"

const emptySupport: BuyOrderSupportData = {
  history: [],
  approvals: [],
  postings: null,
  walletMovements: [],
  inventoryMovements: [],
  journals: [],
  auditLogs: [],
  voucher: null,
}

function unwrap<T>(value: any): T {
  return (value && typeof value === "object" && "data" in value ? value.data : value) as T
}

function arrayPayload<T>(value: any): T[] {
  const payload = unwrap<any>(value)
  return Array.isArray(payload) ? payload : payload?.items ?? []
}

function filterClientSide(items: BuyOrderListItem[], filters: BuyOrderFilters) {
  const term = filters.search?.trim().toLowerCase()
  return items.filter(item => {
    if (filters.status && item.status !== filters.status) return false
    if (filters.buy_order_type && item.buy_order_type !== filters.buy_order_type) return false
    if (filters.currency_id && item.currency_id !== filters.currency_id) return false
    if (filters.branch_id && item.target_branch_id !== filters.branch_id) return false
    if (filters.vault_id && item.target_vault_id !== filters.vault_id) return false
    if (filters.customer_id && item.customer_id !== filters.customer_id) return false
    if (filters.supplier_id && item.supplier_id !== filters.supplier_id) return false
    if (filters.date_from && new Date(item.created_at) < new Date(filters.date_from)) return false
    if (filters.date_to && new Date(item.created_at) > new Date(`${filters.date_to}T23:59:59`)) return false
    if (!term) return true
    return [
      item.buy_order_no,
      item.status,
      item.buy_order_type,
      item.customer_id,
      item.supplier_id,
      item.purchase_request_no,
      item.supplier_reference,
      item.external_reference,
    ].some(value => String(value ?? "").toLowerCase().includes(term))
  })
}

function buildVoucher(order: BuyOrderDetail): BuyOrderVoucher {
  return {
    order_id: order.id,
    order_no: order.buy_order_no,
    order_type: order.buy_order_type,
    status: order.status,
    supplier_id: order.supplier_id,
    customer_id: order.customer_id,
    currency: order.currency,
    items: order.items ?? [],
    subtotal_amount: order.subtotal_amount,
    fee_amount: order.fee_amount,
    tax_amount: order.tax_amount,
    discount_amount: order.discount_amount,
    total_amount: order.total_amount,
    created_at: order.created_at,
    approved_at: order.approved_at,
    posted_at: order.posted_at,
  }
}

export function buyErrorMessage(error: unknown): string {
  if (axios.isAxiosError(error)) {
    const detail = error.response?.data?.detail
    if (typeof detail === "string") return detail
    if (detail && typeof detail === "object") return detail.message || detail.error_code || "Buy order request failed"
    return error.response?.data?.message || error.message
  }
  return error instanceof Error ? error.message : "Buy order request failed"
}

export function printBuyVoucher(voucher: BuyOrderVoucher, filename = "buy-voucher") {
  const printWindow = window.open("", "_blank", "width=920,height=1100")
  if (!printWindow) throw new Error("Popup blocked. Allow popups to print the voucher.")
  const rows = voucher.items.map((item, index) => `
    <tr>
      <td>${index + 1}</td>
      <td>${item.metal_type || "gold"}</td>
      <td>${item.weight_grams}</td>
      <td>${item.quantity}</td>
      <td>${item.price_per_gram}</td>
      <td>${item.premium}</td>
      <td>${item.line_total}</td>
    </tr>
  `).join("")
  printWindow.document.open()
  printWindow.document.write(`
    <!doctype html>
    <html>
      <head>
        <title>${filename}</title>
        <style>
          body { font-family: Arial, sans-serif; color: #111827; margin: 28px; }
          header { display: flex; justify-content: space-between; border-bottom: 2px solid #d4af37; padding-bottom: 16px; margin-bottom: 20px; }
          h1 { font-size: 22px; margin: 0 0 6px; }
          table { width: 100%; border-collapse: collapse; margin-top: 16px; }
          th, td { border: 1px solid #e5e7eb; padding: 8px; font-size: 12px; text-align: left; }
          th { background: #f8fafc; }
          .grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px 24px; font-size: 13px; }
          .totals { width: 320px; margin-left: auto; margin-top: 18px; }
          .totals div { display: flex; justify-content: space-between; padding: 6px 0; border-bottom: 1px solid #e5e7eb; }
          button { margin-top: 24px; padding: 8px 14px; }
          @media print { button { display: none; } body { margin: 18px; } }
        </style>
      </head>
      <body>
        <header>
          <div>
            <h1>Buy Gold Voucher</h1>
            <div>${voucher.order_no}</div>
          </div>
          <div>Status: ${voucher.status}</div>
        </header>
        <section class="grid">
          <div><strong>Order type:</strong> ${voucher.order_type}</div>
          <div><strong>Created:</strong> ${voucher.created_at || "-"}</div>
          <div><strong>Supplier:</strong> ${voucher.supplier_id || "-"}</div>
          <div><strong>Customer:</strong> ${voucher.customer_id || "-"}</div>
          <div><strong>Currency:</strong> ${voucher.currency?.code || voucher.currency?.name_en || "-"}</div>
          <div><strong>Posted:</strong> ${voucher.posted_at || "-"}</div>
        </section>
        <table>
          <thead><tr><th>#</th><th>Metal</th><th>Weight</th><th>Qty</th><th>Price/g</th><th>Premium</th><th>Total</th></tr></thead>
          <tbody>${rows || `<tr><td colspan="7">No items</td></tr>`}</tbody>
        </table>
        <section class="totals">
          <div><span>Subtotal</span><strong>${voucher.subtotal_amount}</strong></div>
          <div><span>Fees</span><strong>${voucher.fee_amount}</strong></div>
          <div><span>Tax</span><strong>${voucher.tax_amount}</strong></div>
          <div><span>Discount</span><strong>${voucher.discount_amount}</strong></div>
          <div><span>Total</span><strong>${voucher.total_amount}</strong></div>
        </section>
        <button onclick="window.print()">Print</button>
      </body>
    </html>
  `)
  printWindow.document.close()
  printWindow.focus()
}

export function useBuyOrders() {
  const [items, setItems] = useState<BuyOrderListItem[]>([])
  const [selected, setSelected] = useState<BuyOrderDetail | null>(null)
  const [support, setSupport] = useState<BuyOrderSupportData>(emptySupport)
  const [total, setTotal] = useState(0)
  const [pages, setPages] = useState(1)
  const [isLoading, setIsLoading] = useState(false)
  const [isSubmitting, setIsSubmitting] = useState(false)
  const [error, setError] = useState<string | null>(null)

  const list = useCallback(async (filters: BuyOrderFilters = {}) => {
    setIsLoading(true)
    setError(null)
    try {
      const response = await api.get(ENDPOINTS.BUY_ORDERS.LIST, {
        params: {
          skip: 0,
          limit: 500,
          req_status: filters.status || undefined,
          buy_order_type: filters.buy_order_type || undefined,
        },
      })
      const allItems = arrayPayload<BuyOrderListItem>(response)
      const filtered = filterClientSide(allItems, filters)
      const page = filters.page ?? 1
      const pageSize = filters.page_size ?? 25
      const paged = filtered.slice((page - 1) * pageSize, page * pageSize)
      setItems(paged)
      setTotal(filtered.length)
      setPages(Math.max(1, Math.ceil(filtered.length / pageSize)))
      return { items: paged, total: filtered.length, page, page_size: pageSize, pages: Math.max(1, Math.ceil(filtered.length / pageSize)) } as PaginatedResponse<BuyOrderListItem>
    } catch (err) {
      setError(buyErrorMessage(err))
      return null
    } finally {
      setIsLoading(false)
    }
  }, [])

  const get = useCallback(async (id: string) => {
    setIsLoading(true)
    setError(null)
    try {
      const detail = unwrap<BuyOrderDetail>(await api.get(ENDPOINTS.BUY_ORDERS.GET_BY_ID(id)))
      setSelected(detail)
      return detail
    } catch (err) {
      setError(buyErrorMessage(err))
      return null
    } finally {
      setIsLoading(false)
    }
  }, [])

  const create = useCallback(async (payload: BuyOrderCreateRequest) => {
    setIsSubmitting(true)
    try {
      return unwrap<BuyOrderDetail>(await api.post(ENDPOINTS.BUY_ORDERS.CREATE, payload))
    } finally {
      setIsSubmitting(false)
    }
  }, [])

  const quote = useCallback((purityId: string, currencyId: string, productId?: string | null) =>
    api.post(ENDPOINTS.BUY_ORDERS.COMPUTE_PRICE, { purity_id: purityId, currency_id: currencyId, product_id: productId || undefined }).then(unwrap<BuyPrice>), [])

  const addItem = useCallback((id: string, payload: BuyOrderItemPayload) =>
    api.post(ENDPOINTS.BUY_ORDERS.ITEMS(id), payload).then(unwrap<BuyOrderItem>), [])

  const deleteItem = useCallback((id: string, itemId: string) =>
    api.del(ENDPOINTS.BUY_ORDERS.ITEM(id, itemId)), [])

  const recalculate = useCallback((id: string) =>
    api.post(ENDPOINTS.BUY_ORDERS.RECALCULATE(id)).then(unwrap<BuyOrderDetail>), [])

  const act = useCallback(async (id: string, action: string, options: { reason?: string; receiving_vault_id?: string; customer_user_id?: string } = {}) => {
    const e = ENDPOINTS.BUY_ORDERS
    const endpoint: Record<string, string> = {
      submit: e.SUBMIT_FOR_REVIEW(id),
      review: e.SUBMIT_FOR_APPROVAL(id),
      approve: e.APPROVE(id),
      reject: e.REJECT(id),
      cancel: e.CANCEL(id),
      post: e.POST_APPROVAL(id),
      send: e.SEND_TO_SUPPLIER(id),
      partial: e.MARK_PARTIALLY_SUPPLIED(id),
      full: e.MARK_FULLY_SUPPLIED(id),
      close: e.CLOSE(id),
      "post-supply": e.POST_SUPPLY(id),
      "post-buyback": e.POST_BUYBACK(id),
      reverse: e.REVERSE(id),
    }
    const body =
      action === "cancel" || action === "reverse" ? { reason: options.reason } :
      action === "post" ? undefined :
      action === "post-supply" ? { receiving_vault_id: options.receiving_vault_id || null } :
      action === "post-buyback" ? (options.customer_user_id ? { customer_user_id: options.customer_user_id } : {}) :
      { note: options.reason || null }
    setIsSubmitting(true)
    try {
      return unwrap<BuyOrderDetail | BuyOrderPostingResult>(await api.post(endpoint[action], body))
    } finally {
      setIsSubmitting(false)
    }
  }, [])

  const loadSupport = useCallback(async (id: string, detail?: BuyOrderDetail | null) => {
    const e = ENDPOINTS.BUY_ORDERS
    const requests = [
      api.get(e.STATUS_HISTORY(id)),
      api.get(e.APPROVALS(id)),
      api.get(e.POSTINGS(id)),
      api.get(ENDPOINTS.AUDIT_LOGS.LIST, { params: { entity_type: "buy_order", entity_id: id } }),
    ]
    const results = await Promise.allSettled(requests)
    const value = (index: number, fallback: any) =>
      results[index].status === "fulfilled" ? unwrap<any>((results[index] as PromiseFulfilledResult<any>).value) : fallback
    const history = value(0, []) as StatusHistory[]
    const approvals = value(1, []) as ApprovalRequest[]
    const postings = value(2, null) as BuyOrderPostingResult | null
    const auditLogs = value(3, { items: [] }).items ?? []
    const next: BuyOrderSupportData = {
      history,
      approvals,
      postings,
      walletMovements: [],
      inventoryMovements: [],
      journals: [],
      auditLogs,
      voucher: detail ? buildVoucher(detail) : null,
    }
    setSupport(next)
    return next
  }, [])

  return {
    items,
    selected,
    support,
    total,
    pages,
    isLoading,
    isSubmitting,
    error,
    list,
    get,
    create,
    quote,
    addItem,
    deleteItem,
    recalculate,
    act,
    loadSupport,
  }
}
