import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import type QuoteModuleService from "../../../../modules/quote/service"
import { QUOTE_MODULE } from "../../../../modules/quote"
import { createQuoteReference } from "../../../../lib/quote-reference"

type QuoteItemInput = {
  line_id?: string
  product_id?: string
  variant_id?: string
  product_title?: string
  variant_title?: string
  quantity?: number
  unit_price?: number | null
  total?: number | null
  thumbnail?: string | null
  metadata?: Record<string, unknown> | null
}

type CreateQuoteBody = {
  customer_id?: string
  customer_email?: string
  cart_id?: string
  currency_code?: string | null
  subtotal?: number | null
  shipping_total?: number | null
  total?: number | null
  event_date?: string | null
  items?: QuoteItemInput[]
  cart_snapshot?: Record<string, unknown> | null
}

function toMoneyValue(value: unknown) {
  return typeof value === "number" && Number.isFinite(value) ? value : null
}

function toText(value: unknown) {
  return typeof value === "string" && value.trim() ? value.trim() : null
}

function readSanityEnv() {
  return {
    projectId:
      process.env.SANITY_PROJECT_ID ||
      process.env.SANITY_STUDIO_PROJECT_ID ||
      process.env.NEXT_PUBLIC_SANITY_PROJECT_ID ||
      "",
    dataset:
      process.env.SANITY_DATASET ||
      process.env.SANITY_STUDIO_DATASET ||
      process.env.NEXT_PUBLIC_SANITY_DATASET ||
      "production",
    apiVersion: process.env.SANITY_API_VERSION || process.env.NEXT_PUBLIC_SANITY_API_VERSION || "2025-01-01",
    token: process.env.SANITY_API_READ_TOKEN || process.env.SANITY_API_WRITE_TOKEN || "",
  }
}

async function getQuoteNumberPrefixTemplate() {
  const sanityEnv = readSanityEnv()

  if (!sanityEnv.projectId) {
    return null
  }

  const query = `*[_type == "quoteSettings" && _id == "quote-settings"][0]{
    quoteNumberPrefixTemplate
  }`

  const url = new URL(`https://${sanityEnv.projectId}.api.sanity.io/v${sanityEnv.apiVersion}/data/query/${sanityEnv.dataset}`)
  url.searchParams.set("query", query)

  const headers: Record<string, string> = {
    accept: "application/json",
  }

  if (sanityEnv.token) {
    headers.authorization = `Bearer ${sanityEnv.token}`
  }

  try {
    const response = await fetch(url, {
      method: "GET",
      headers,
      cache: "no-store",
    })

    if (!response.ok) {
      return null
    }

    const json = (await response.json()) as { result?: { quoteNumberPrefixTemplate?: string | null } | null }
    return toText(json.result?.quoteNumberPrefixTemplate) || null
  } catch {
    return null
  }
}

function getCreatedAtValue(input: { created_at?: Date | string | null }) {
  const raw = input.created_at
  if (!raw) {
    return 0
  }

  const date = raw instanceof Date ? raw : new Date(raw)
  return Number.isNaN(date.getTime()) ? 0 : date.getTime()
}

function normalizeItems(items: QuoteItemInput[] | undefined) {
  return (items || []).map((item) => ({
    line_id: toText(item.line_id),
    product_id: toText(item.product_id),
    variant_id: toText(item.variant_id),
    product_title: toText(item.product_title),
    variant_title: toText(item.variant_title),
    quantity: typeof item.quantity === "number" && Number.isFinite(item.quantity) ? Math.max(1, Math.round(item.quantity)) : 1,
    unit_price: toMoneyValue(item.unit_price),
    total: toMoneyValue(item.total),
    thumbnail: toText(item.thumbnail),
    metadata: item.metadata && typeof item.metadata === "object" ? item.metadata : null,
  }))
}

export async function GET(req: MedusaRequest, res: MedusaResponse) {
  const quoteModuleService = req.scope.resolve<QuoteModuleService>(QUOTE_MODULE)
  const customerId = toText(req.query.customer_id)
  const customerEmail = toText(req.query.customer_email)?.toLowerCase() || null

  if (!customerId && !customerEmail) {
    return res.status(400).json({
      message: "customer_id or customer_email is required.",
    })
  }

  const filters: Record<string, string> = {}
  if (customerId) {
    filters.customer_id = customerId
  } else if (customerEmail) {
    filters.customer_email = customerEmail
  }

  const quotes = await quoteModuleService.listQuotes(filters)
  const sortedQuotes = [...quotes].sort((a, b) => {
    return getCreatedAtValue(b) - getCreatedAtValue(a)
  })

  res.json({
    quotes: sortedQuotes.map((quote) => ({
      ...quote,
      items: JSON.parse((quote.items_snapshot as string) || "[]"),
      cart_snapshot: JSON.parse((quote.cart_snapshot as string) || "{}"),
    })),
  })
}

export async function POST(req: MedusaRequest<CreateQuoteBody>, res: MedusaResponse) {
  const quoteModuleService = req.scope.resolve<QuoteModuleService>(QUOTE_MODULE)
  const customerId = toText(req.body.customer_id)
  const customerEmail = toText(req.body.customer_email)?.toLowerCase() || null
  const cartId = toText(req.body.cart_id)
  const items = normalizeItems(req.body.items)

  if (!customerId || !customerEmail || !cartId || items.length === 0) {
    return res.status(400).json({
      message: "customer_id, customer_email, cart_id and items are required.",
    })
  }

  const quoteNumberPrefixTemplate = await getQuoteNumberPrefixTemplate()

  const createdQuote = await quoteModuleService.createQuotes({
    reference: createQuoteReference(quoteNumberPrefixTemplate),
    status: "saved",
    customer_id: customerId,
    customer_email: customerEmail,
    cart_id: cartId,
    currency_code: toText(req.body.currency_code),
    subtotal: toMoneyValue(req.body.subtotal),
    shipping_total: toMoneyValue(req.body.shipping_total),
    total: toMoneyValue(req.body.total),
    event_date: toText(req.body.event_date),
    items_snapshot: JSON.stringify(items),
    cart_snapshot: JSON.stringify(req.body.cart_snapshot && typeof req.body.cart_snapshot === "object" ? req.body.cart_snapshot : {}),
  })

  res.status(201).json({
    quote: {
      ...createdQuote,
      items,
    },
  })
}

export async function DELETE(req: MedusaRequest, res: MedusaResponse) {
  const quoteModuleService = req.scope.resolve<QuoteModuleService>(QUOTE_MODULE)
  const quoteId = toText(req.query.quote_id)
  const customerId = toText(req.query.customer_id)
  const customerEmail = toText(req.query.customer_email)?.toLowerCase() || null

  if (!quoteId || (!customerId && !customerEmail)) {
    return res.status(400).json({
      message: "quote_id and customer identity are required.",
    })
  }

  const filters: Record<string, string> = {
    id: quoteId,
  }

  if (customerId) {
    filters.customer_id = customerId
  } else if (customerEmail) {
    filters.customer_email = customerEmail
  }

  const quotes = await quoteModuleService.listQuotes(filters)
  const quote = quotes.find((item) => item.id === quoteId)

  if (!quote) {
    return res.status(404).json({
      message: "Quote not found.",
    })
  }

  await quoteModuleService.deleteQuotes([quote.id])

  res.status(200).json({
    id: quote.id,
    object: "quote",
    deleted: true,
  })
}
