import { NextResponse } from 'next/server'
import { Prisma } from '@prisma/client'
import { prisma } from '@/lib/prisma'
import { checkAdminAuth } from '@/lib/auth-check'
import { validateOrderStatus, ValidationError } from '@/lib/validation'
import type { ColorVariant, SizeVariant } from '@/types'

type Params = {
  params: Promise<{
    id: string
  }>
}

type UpdateOrderItemInput = {
  productId: string
  quantity: number
  price: number | string
  selectedColor?: string | null
  selectedSize?: string | null
}

type UpdateOrderBody = {
  status?: string
  customerName?: string
  customerEmail?: string
  customerPhone?: string
  customerAddress?: string
  customerCity?: string
  customerZip?: string
  shippingMethod?: string
  notes?: string | null
  total?: number | string
  items?: UpdateOrderItemInput[]
}

const toNumber = (value: number | string): number =>
  typeof value === 'string' ? parseFloat(value) : value

const toSizeVariants = (value: unknown): SizeVariant[] =>
  Array.isArray(value) ? (value as SizeVariant[]) : []

const toColorVariants = (value: unknown): ColorVariant[] =>
  Array.isArray(value) ? (value as ColorVariant[]) : []

// GET /api/admin/orders/[id] - Get single order (Admin only)
export async function GET(_request: Request, { params }: Params) {
  const authError = await checkAdminAuth()
  if (authError) return authError

  try {
    const { id } = await params
    const order = await prisma.order.findUnique({
      where: { id },
      include: {
        items: {
          include: {
            product: true,
          },
        },
      },
    })

    if (!order) {
      return NextResponse.json({ error: 'Order not found' }, { status: 404 })
    }

    return NextResponse.json(order)
  } catch (error) {
    console.error('Error fetching order:', error)
    return NextResponse.json({ error: 'Failed to fetch order' }, { status: 500 })
  }
}

// PUT /api/admin/orders/[id] - Update order (all fields) (Admin only)
export async function PUT(request: Request, { params }: Params) {
  const authError = await checkAdminAuth()
  if (authError) return authError

  try {
    const { id } = await params
    const body = (await request.json()) as UpdateOrderBody

    // Validate order status
    const status = validateOrderStatus(body.status)

    // Get current order to check previous status
    const currentOrder = await prisma.order.findUnique({
      where: { id },
      include: {
        items: {
          include: {
            product: true,
          },
        },
      },
    })

    if (!currentOrder) {
      return NextResponse.json({ error: 'Order not found' }, { status: 404 })
    }

    // Check if status is changing from pre-shipped to shipped/delivered
    const preShippedStatuses = ['pending', 'processing']
    const shippedStatuses = ['shipped', 'delivered']
    const shouldReduceStock =
      preShippedStatuses.includes(currentOrder.status) &&
      shippedStatuses.includes(status)

    // Build update data for all editable fields
    const updateData: Prisma.OrderUpdateInput = { status }

    if (body.customerName !== undefined) updateData.customerName = body.customerName
    if (body.customerEmail !== undefined) updateData.customerEmail = body.customerEmail
    if (body.customerPhone !== undefined) updateData.customerPhone = body.customerPhone
    if (body.customerAddress !== undefined) updateData.customerAddress = body.customerAddress
    if (body.customerCity !== undefined) updateData.customerCity = body.customerCity
    if (body.customerZip !== undefined) updateData.customerZip = body.customerZip
    if (body.shippingMethod !== undefined) updateData.shippingMethod = body.shippingMethod
    if (body.notes !== undefined) updateData.notes = body.notes || null
    if (body.total !== undefined) updateData.total = toNumber(body.total)

    // Handle items update: delete old items and create new ones
    if (Array.isArray(body.items)) {
      const itemsToCreate: Prisma.OrderItemUncheckedCreateWithoutOrderInput[] = body.items.map((item) => ({
        productId: item.productId,
        quantity: item.quantity,
        price: toNumber(item.price),
        selectedColor: item.selectedColor || null,
        selectedSize: item.selectedSize || null,
      }))
      updateData.items = {
        deleteMany: {},
        create: itemsToCreate,
      }
    }

    // Update order
    const order = await prisma.order.update({
      where: { id },
      data: updateData,
      include: {
        items: {
          include: {
            product: true,
          },
        },
      },
    })

    // Reduce stock if status changed to shipped/delivered
    if (shouldReduceStock) {
      for (const orderItem of currentOrder.items) {
        const item = orderItem
        const product = item.product
        let handledByVariant = false

        // Both size + color: use nested colorStocks inside the size variant
        if (item.selectedSize && item.selectedColor && product.sizes) {
          const sizes = toSizeVariants(product.sizes)
          const sizeVariant = sizes.find((s) => s.name === item.selectedSize)
          if (sizeVariant?.colorStocks) {
            // Decrement the specific colorStocks entry
            const updatedSizes: SizeVariant[] = sizes.map((size) => {
              if (size.name === item.selectedSize) {
                const colorStocks = size.colorStocks ?? []
                return {
                  ...size,
                  colorStocks: colorStocks.map((cs) =>
                    cs.colorName === item.selectedColor
                      ? { ...cs, stock: Math.max(0, cs.stock - item.quantity) }
                      : cs
                  ),
                }
              }
              return size
            })
            await prisma.product.update({
              where: { id: item.productId },
              data: { sizes: updatedSizes as unknown as Prisma.InputJsonValue },
            })
            handledByVariant = true
          }
        }

        // Size only (no colorStocks)
        if (!handledByVariant && item.selectedSize && product.sizes) {
          const sizes = toSizeVariants(product.sizes)
          const updatedSizes: SizeVariant[] = sizes.map((size) => {
            if (size.name === item.selectedSize) {
              return { ...size, stock: Math.max(0, size.stock - item.quantity) }
            }
            return size
          })
          await prisma.product.update({
            where: { id: item.productId },
            data: { sizes: updatedSizes as unknown as Prisma.InputJsonValue },
          })
          handledByVariant = true
        }

        // Color only (no sizes)
        if (!handledByVariant && item.selectedColor && product.colors) {
          const colors = toColorVariants(product.colors)
          const updatedColors: ColorVariant[] = colors.map((color) => {
            if (color.name === item.selectedColor) {
              return { ...color, stock: Math.max(0, color.stock - item.quantity) }
            }
            return color
          })
          await prisma.product.update({
            where: { id: item.productId },
            data: { colors: updatedColors as unknown as Prisma.InputJsonValue },
          })
          handledByVariant = true
        }

        // Reduce flat stock only if no variant was used
        if (!handledByVariant) {
          await prisma.product.update({
            where: { id: item.productId },
            data: { stock: { decrement: item.quantity } },
          })
        }
      }
    }

    return NextResponse.json(order)
  } catch (error) {
    console.error('Error updating order:', error)
    if (error instanceof ValidationError) {
      return NextResponse.json({ error: error.message }, { status: 400 })
    }
    return NextResponse.json({ error: 'Failed to update order' }, { status: 500 })
  }
}

// DELETE /api/admin/orders/[id] - Delete order (Admin only)
export async function DELETE(_request: Request, { params }: Params) {
  const authError = await checkAdminAuth()
  if (authError) return authError

  try {
    const { id } = await params

    const order = await prisma.order.findUnique({ where: { id } })
    if (!order) {
      return NextResponse.json({ error: 'Order not found' }, { status: 404 })
    }

    await prisma.order.delete({ where: { id } })

    return NextResponse.json({ success: true })
  } catch (error) {
    console.error('Error deleting order:', error)
    return NextResponse.json({ error: 'Failed to delete order' }, { status: 500 })
  }
}
