import { z } from 'zod'
import { and, type Filter, type Invoice, type Order, type Shipment } from '@znet/magento'
import { SCOPES } from '../config.js'
import { maskEmail, maskName, presentAddress } from '../pii.js'
import { defineTool, type ToolContext } from '../registry.js'

const INVOICE_STATE: Record<number, string> = { 1: 'open', 2: 'paid', 3: 'canceled' }

const canSeePii = (ctx: ToolContext) => ctx.caller.scopes.includes(SCOPES.ORDERS_PII)

function customerOf(o: Order, pii: boolean) {
  return pii
    ? { name: [o.customer_firstname, o.customer_lastname].filter(Boolean).join(' ') || null, email: o.customer_email, guest: Boolean(o.customer_is_guest) }
    : { name: maskName(o.customer_firstname, o.customer_lastname), email: maskEmail(o.customer_email), guest: Boolean(o.customer_is_guest) }
}

function orderSummary(o: Order, pii: boolean) {
  return {
    orderNumber: o.increment_id,
    createdAt: o.created_at,
    status: o.status,
    state: o.state,
    customer: customerOf(o, pii),
    grandTotal: o.grand_total,
    currency: o.order_currency_code,
    itemCount: o.items.filter(i => !i.parent_item_id).length,
  }
}

function fulfilmentOf(o: Order) {
  const lines = o.items.filter(i => !i.parent_item_id)
  const ordered = lines.reduce((n, i) => n + i.qty_ordered - i.qty_canceled, 0)
  const shipped = lines.reduce((n, i) => n + i.qty_shipped, 0)
  const invoiced = lines.reduce((n, i) => n + i.qty_invoiced, 0)
  const state = (done: number) => (done <= 0 ? 'none' : done >= ordered ? 'full' : 'partial')
  return { invoiced: state(invoiced), shipped: state(shipped), unitsOrdered: ordered, unitsInvoiced: invoiced, unitsShipped: shipped }
}

/** YYYY-MM-DD → Magento datetime bounds (UTC). */
const dayStart = (d: string) => `${d} 00:00:00`
const dayEnd = (d: string) => `${d} 23:59:59`
const isoDate = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'use YYYY-MM-DD')

export const orderTools = [
  defineTool({
    name: 'search_orders',
    title: 'Search orders',
    description:
      'Search orders live in Magento by status, customer email and/or date range (newest first). Returns order number, date, status, customer, total. Customer details are masked unless you have PII access.',
    scope: SCOPES.ORDERS_READ,
    input: {
      status: z.string().max(64).optional().describe('Order status code, e.g. pending, processing, complete, canceled, holded'),
      customer_email: z.email().optional().describe('Exact customer email'),
      created_from: isoDate.optional().describe('Created on/after (YYYY-MM-DD, UTC)'),
      created_to: isoDate.optional().describe('Created on/before (YYYY-MM-DD, UTC)'),
      limit: z.number().int().min(1).max(50).default(20),
      page: z.number().int().min(1).max(500).default(1),
    },
    run: async (a, ctx) => {
      const filters: Array<Filter | undefined> = [
        a.status ? { field: 'status', value: a.status } : undefined,
        a.customer_email ? { field: 'customer_email', value: a.customer_email } : undefined,
        a.created_from ? { field: 'created_at', value: dayStart(a.created_from), condition: 'gteq' } : undefined,
        a.created_to ? { field: 'created_at', value: dayEnd(a.created_to), condition: 'lteq' } : undefined,
      ]
      const res = await ctx.magento.searchOrders({
        filterGroups: and(...filters),
        sortOrders: [{ field: 'created_at', direction: 'DESC' }],
        pageSize: a.limit,
        currentPage: a.page,
      })
      const items = res.items ?? []
      return { total: res.total_count, page: a.page, items: items.map(o => orderSummary(o, canSeePii(ctx))), source: 'magento-live' }
    },
  }),

  defineTool({
    name: 'get_order',
    title: 'Get order',
    description:
      'Live order detail by order number (increment id, e.g. "000012345"): status and history, items with ordered/invoiced/shipped/refunded quantities, totals, payment method, invoices, shipments with carrier tracking numbers, and addresses. Answers "what is the status", "has it been invoiced/shipped", "what is the tracking number".',
    scope: SCOPES.ORDERS_READ,
    input: { order_number: z.string().min(1).max(64).describe('Order increment id as shown to customers') },
    run: async (a, ctx) => {
      const order = await ctx.magento.orderByIncrementId(a.order_number.trim())
      if (!order) return { found: false, orderNumber: a.order_number }
      const pii = canSeePii(ctx)
      const [invoices, shipments] = await Promise.all([
        ctx.magento.invoicesForOrder(order.entity_id),
        ctx.magento.shipmentsForOrder(order.entity_id),
      ])
      const shipping = order.extension_attributes?.shipping_assignments?.[0]?.shipping

      return {
        found: true,
        ...orderSummary(order, pii),
        updatedAt: order.updated_at,
        fulfilment: fulfilmentOf(order),
        totals: {
          subtotal: order.subtotal, shipping: order.shipping_amount, discount: order.discount_amount, tax: order.tax_amount,
          grandTotal: order.grand_total, paid: order.total_paid ?? 0, refunded: order.total_refunded ?? 0,
        },
        paymentMethod: order.payment?.method ?? null,
        shippingMethod: order.shipping_description ?? shipping?.method ?? null,
        items: order.items
          .filter(i => !i.parent_item_id)
          .map(i => ({
            sku: i.sku, name: i.name, type: i.product_type, price: i.price, rowTotalInclTax: i.row_total_incl_tax ?? null,
            qtyOrdered: i.qty_ordered, qtyInvoiced: i.qty_invoiced, qtyShipped: i.qty_shipped, qtyRefunded: i.qty_refunded, qtyCanceled: i.qty_canceled,
          })),
        invoices: (invoices.items ?? []).map((inv: Invoice) => ({
          number: inv.increment_id, createdAt: inv.created_at, state: INVOICE_STATE[inv.state] ?? String(inv.state), total: inv.grand_total,
        })),
        shipments: (shipments.items ?? []).map((s: Shipment) => ({
          number: s.increment_id,
          createdAt: s.created_at,
          tracking: (s.tracks ?? []).map(t => ({ carrier: t.title || t.carrier_code, number: t.track_number })),
          items: (s.items ?? []).map(i => ({ sku: i.sku, qty: i.qty })),
        })),
        history: (order.status_histories ?? [])
          .filter(h => h.comment || h.status)
          .map(h => ({ at: h.created_at, status: h.status, comment: h.comment, customerNotified: Boolean(h.is_customer_notified) })),
        billingAddress: presentAddress(order.billing_address, pii),
        shippingAddress: presentAddress(shipping?.address, pii),
        piiMasked: !pii,
        source: 'magento-live',
      }
    },
  }),

  defineTool({
    name: 'get_customer_orders',
    title: 'Customer order history',
    description: 'All orders placed with a customer email (newest first), with status, totals and fulfilment state. Live from Magento.',
    scope: SCOPES.ORDERS_READ,
    input: {
      customer_email: z.email(),
      limit: z.number().int().min(1).max(50).default(20),
    },
    run: async (a, ctx) => {
      const res = await ctx.magento.searchOrders({
        filterGroups: and({ field: 'customer_email', value: a.customer_email }),
        sortOrders: [{ field: 'created_at', direction: 'DESC' }],
        pageSize: a.limit,
      })
      const orders = res.items ?? []
      const pii = canSeePii(ctx)
      return {
        customer: pii ? a.customer_email : maskEmail(a.customer_email),
        totalOrders: res.total_count,
        lifetimeValue: orders.length === res.total_count ? orders.reduce((n, o) => n + o.grand_total, 0) : null,
        orders: orders.map(o => ({ ...orderSummary(o, pii), fulfilment: fulfilmentOf(o) })),
        source: 'magento-live',
      }
    },
  }),
]
