import { NextResponse } from "next/server";
import { createClient } from "@/lib/supabase-server";
import { canCompany, getCompanyContext } from "@/lib/company-context";
import { calculateEffectiveQuantity, checkSaleQuantityLimits } from "@/lib/price-tiers";
import { minimoDaLinhaGravada } from "@/lib/adicionais";

export const runtime = "nodejs";

function formatQuantityValue(value: number) {
  return Number(value.toFixed(3)).toString().replace(".", ",");
}

function buildQuantityRuleMessage(product: {
  min_sale_qty_enabled?: boolean | null;
  min_sale_qty?: number | null;
  max_sale_qty_enabled?: boolean | null;
  max_sale_qty?: number | null;
  allowed_sale_qty_enabled?: boolean | null;
  allowed_sale_quantities?: number[] | null;
}, effectiveQuantity: number) {
  const quantityCheck = checkSaleQuantityLimits({
    min_sale_qty_enabled: product.min_sale_qty_enabled,
    min_sale_qty: product.min_sale_qty,
    max_sale_qty_enabled: product.max_sale_qty_enabled,
    max_sale_qty: product.max_sale_qty,
    allowed_sale_qty_enabled: product.allowed_sale_qty_enabled,
    allowed_sale_quantities: product.allowed_sale_quantities,
    effectiveQuantity,
  });

  if (quantityCheck.isBelowMin && quantityCheck.minQty !== null) {
    return `Quantidade mínima atual: ${formatQuantityValue(quantityCheck.minQty)}.`;
  }
  if (quantityCheck.isAboveMax && quantityCheck.maxQty !== null) {
    return `Quantidade máxima atual: ${formatQuantityValue(quantityCheck.maxQty)}.`;
  }
  if (quantityCheck.isNotAllowedValue && quantityCheck.allowedQuantities.length > 0) {
    return `Quantidades permitidas atualmente: ${quantityCheck.allowedQuantities.map(formatQuantityValue).join(", ")}.`;
  }
  return null;
}

function extractCatalogOrderShipping(cartPayload: unknown) {
  if (!cartPayload || typeof cartPayload !== "object" || Array.isArray(cartPayload)) {
    return { amount: 0, details: null as Record<string, unknown> | null };
  }
  const shipping = (cartPayload as { shipping?: unknown }).shipping;
  if (!shipping || typeof shipping !== "object" || Array.isArray(shipping)) {
    return { amount: 0, details: null as Record<string, unknown> | null };
  }
  const shippingRecord = shipping as Record<string, unknown>;
  const option = shippingRecord.option && typeof shippingRecord.option === "object" && !Array.isArray(shippingRecord.option)
    ? (shippingRecord.option as Record<string, unknown>)
    : null;
  const amountCandidate = Number(shippingRecord.amount ?? option?.price ?? 0);
  const amount = Number.isFinite(amountCandidate) && amountCandidate > 0 ? amountCandidate : 0;
  /*
    Retirada no balcao costuma custar zero. Amarrar o detalhe ao valor fazia o
    orcamento nascer sem nenhum vestigio de que o cliente vai buscar na loja: a
    equipe so via frete zerado e presumia entrega.
  */
  const hasChosenOption = Boolean(option?.id || option?.provider);
  return {
    amount,
    details: amount > 0 || hasChosenOption ? { ...shippingRecord, amount } : null,
  };
}

type CatalogOrderItemRow = {
  id: string;
  product_id: string | null;
  title: string;
  description: string | null;
  quantity: number;
  unit_type: string | null;
  width_m: number | null;
  height_m: number | null;
  length_m: number | null;
  unit_price: number;
  total_price: number;
  selected_options: unknown;
  raw_item?: { valor_minimo_aplicado?: number | string | null; valor_sem_minimo?: number | string | null } | null;
};

async function ensureCatalogPlaceholderClient(
  supabase: Awaited<ReturnType<typeof createClient>>,
  tenantId: string
) {
  const { data: existing, error: existingError } = await supabase
    .from("clients")
    .select("id,user_id,name,company_name,is_deleted")
    .eq("user_id", tenantId)
    .eq("is_system_placeholder", true)
    .order("created_at", { ascending: true })
    .limit(1);

  if (existingError) throw new Error(existingError.message);

  const activeExisting = (existing || []).find((client) => !client.is_deleted);
  if (activeExisting?.id) {
    return {
      id: String(activeExisting.id),
      user_id: String(activeExisting.user_id),
      name: activeExisting.name || null,
      company_name: activeExisting.company_name || null,
    };
  }

  const now = new Date().toISOString();
  const payload = {
    user_id: tenantId,
    name: "Cliente Catálogo",
    company_name: "Cliente Catálogo",
    type: "pf",
    document: null,
    whatsapp: "",
    email: "",
    notes: "Cliente técnico para pedidos do catálogo sem vínculo.",
    tags: ["catalog"],
    whatsapp_notify: false,
    active: true,
    address_zip: null,
    address_state: null,
    address_city: null,
    address_neighborhood: null,
    address_street: null,
    address_number: null,
    address_complement: null,
    created_at: now,
    updated_at: now,
    is_system_placeholder: true,
  };

  const { data: created, error: createError } = await supabase
    .from("clients")
    .insert([payload])
    .select("id,user_id,name,company_name")
    .single();

  if (createError || !created) {
    throw new Error(createError?.message || "Não foi possível criar cliente técnico do catálogo.");
  }

  return {
    id: String(created.id),
    user_id: String(created.user_id),
    name: created.name || null,
    company_name: created.company_name || null,
  };
}

export async function POST(req: Request) {
  const supabase = await createClient();
  const {
    data: { user },
  } = await supabase.auth.getUser();
  if (!user) return NextResponse.json({ error: "Não autenticado." }, { status: 401 });

  const body = await req.json().catch(() => ({}));
  const catalogOrderId = typeof body?.catalog_order_id === "string" ? body.catalog_order_id.trim() : "";
  if (!catalogOrderId) {
    return NextResponse.json({ error: "Pedido do catálogo não informado." }, { status: 400 });
  }

  const companyCtx = await getCompanyContext(supabase, user);
  if (!canCompany(companyCtx, user.id, "catalog.orders.write") || !canCompany(companyCtx, user.id, "orders.write")) {
    return NextResponse.json({ error: "Sem permissão." }, { status: 403 });
  }

  const tenantIds = companyCtx.tenantIds?.length ? companyCtx.tenantIds : [user.id];
  const { data: orderRow, error: orderError } = await supabase
    .from("catalog_orders")
    .select("id,user_id,number,status,client_id,customer_name,customer_whatsapp,notes,subtotal,discount,total,currency,coupon_code,cart_payload,catalog_order_items(id,product_id,title,description,quantity,unit_type,width_m,height_m,length_m,unit_price,total_price,selected_options,raw_item)")
    .eq("id", catalogOrderId)
    .in("user_id", tenantIds)
    .maybeSingle();

  if (orderError) return NextResponse.json({ error: orderError.message }, { status: 400 });
  if (!orderRow) return NextResponse.json({ error: "Pedido do catálogo não encontrado." }, { status: 404 });

  const catalogOrder = orderRow as {
    id: string;
    user_id: string;
    number: number;
    status: "pending" | "approved" | "canceled";
    client_id: string | null;
    customer_name: string | null;
    customer_whatsapp: string | null;
    notes: string | null;
    subtotal: number | null;
    discount: number | null;
    total: number | null;
    currency: string | null;
    coupon_code: string | null;
    cart_payload?: unknown;
    catalog_order_items: CatalogOrderItemRow[] | null;
  };

  if (catalogOrder.status !== "pending") {
    return NextResponse.json({ error: "Somente pedidos pendentes podem ser aprovados." }, { status: 400 });
  }

  const items = (catalogOrder.catalog_order_items || []).filter((item) => Number(item.quantity) > 0);
  if (items.length === 0) {
    return NextResponse.json({ error: "Pedido sem itens válidos para aprovação." }, { status: 400 });
  }

  let clientId = catalogOrder.client_id;
  if (clientId) {
    const { data: client, error: clientError } = await supabase
      .from("clients")
      .select("id,is_deleted")
      .eq("id", clientId)
      .in("user_id", tenantIds)
      .maybeSingle();
    if (clientError) return NextResponse.json({ error: clientError.message }, { status: 400 });
    if (!client || (client as { is_deleted?: boolean | null }).is_deleted) {
      clientId = null;
    }
  }

  if (!clientId) {
    try {
      const placeholder = await ensureCatalogPlaceholderClient(supabase, catalogOrder.user_id);
      clientId = placeholder.id;
    } catch (error) {
      const message = error instanceof Error ? error.message : "Não foi possível preparar cliente técnico.";
      return NextResponse.json({ error: message }, { status: 400 });
    }
  }

  const { data: maxQuote } = await supabase
    .from("quotes")
    .select("number")
    .eq("user_id", catalogOrder.user_id)
    .order("number", { ascending: false })
    .limit(1)
    .maybeSingle();
  const quoteNumber = Math.max(1, Number((maxQuote as { number?: number } | null)?.number || 0) + 1);
  const now = new Date().toISOString();
  const shippingSnapshot = extractCatalogOrderShipping(catalogOrder.cart_payload);

  const internalNotes = ["origem:catalogo", catalogOrder.coupon_code ? `cupom:${catalogOrder.coupon_code}` : ""]
    .filter(Boolean)
    .join("\n");

  const { data: createdQuote, error: quoteError } = await supabase
    .from("quotes")
    .insert([
      {
        user_id: catalogOrder.user_id,
        client_id: clientId,
        number: quoteNumber,
        status: "draft",
        title: `Pedido do catálogo #${catalogOrder.number}`,
        description: null,
        currency: catalogOrder.currency || "BRL",
        subtotal: Number(catalogOrder.subtotal || 0),
        discount: Number(catalogOrder.discount || 0),
        shipping: shippingSnapshot.amount,
        shipping_details: shippingSnapshot.details,
        list_price_mode: false,
        total: Number(catalogOrder.total || 0),
        expires_at: null,
        delivery_date: null,
        notes: catalogOrder.notes || null,
        internal_notes: internalNotes,
        created_at: now,
        updated_at: now,
      },
    ])
    .select("id")
    .single();

  if (quoteError || !createdQuote) {
    return NextResponse.json({ error: quoteError?.message || "Não foi possível criar orçamento técnico." }, { status: 400 });
  }

  const quoteId = String((createdQuote as { id: string }).id);
  const productIds = Array.from(
    new Set(items.map((item) => item.product_id).filter((value): value is string => typeof value === "string" && value.length > 0))
  );
  const productsById = new Map<string, {
    id: string;
    min_sale_qty_enabled?: boolean | null;
    min_sale_qty?: number | null;
    max_sale_qty_enabled?: boolean | null;
    max_sale_qty?: number | null;
    allowed_sale_qty_enabled?: boolean | null;
    allowed_sale_quantities?: number[] | null;
  }>();

  if (productIds.length > 0) {
    const { data: productsData, error: productsError } = await supabase
      .from("products")
      .select("id,min_sale_qty_enabled,min_sale_qty,max_sale_qty_enabled,max_sale_qty,allowed_sale_qty_enabled,allowed_sale_quantities")
      .in("id", productIds)
      .eq("user_id", catalogOrder.user_id);

    if (productsError) {
      await supabase.from("quotes").delete().eq("id", quoteId);
      return NextResponse.json({ error: productsError.message }, { status: 400 });
    }

    for (const product of productsData || []) {
      productsById.set(String(product.id), product);
    }
  }

  const quoteItems = items.map((item, index) => {
    const product = item.product_id ? productsById.get(item.product_id) : null;
    const effectiveQuantity = calculateEffectiveQuantity({
      quantity: Number(item.quantity || 0),
      unit_type: item.unit_type || "unit",
      width_m: item.width_m,
      height_m: item.height_m,
      length_m: item.length_m,
    });
    const quantityRuleMessage = product ? buildQuantityRuleMessage(product, effectiveQuantity) : null;
    const baseDescription = String(item.description || "").trim();
    const fallbackDescription = quantityRuleMessage
      ? [baseDescription, `Item convertido para avulso ao revisar pedido do catálogo. ${quantityRuleMessage}`].filter(Boolean).join("\n")
      : baseDescription || null;
    const minimo = minimoDaLinhaGravada(item.raw_item);

    return {
    quote_id: quoteId,
    position: index + 1,
    product_id: quantityRuleMessage ? null : item.product_id,
    unit_type: item.unit_type || "unit",
    width_m: item.width_m,
    height_m: item.height_m,
    length_m: item.length_m,
    title: item.title,
    description: fallbackDescription,
    quantity: Number(item.quantity || 0),
    unit_price: Number(item.unit_price || 0),
    unit_cost: 0,
    /* Pela quantidade efetiva: no item por m², preço do metro × área × peças.
       Com o valor mínimo do item (a loja grava no raw_item), a linha vale o mínimo. */
    line_total: minimo ? minimo.minimo : Number(item.unit_price || 0) * effectiveQuantity,
    selected_options: item.selected_options || null,
    valor_minimo_aplicado: minimo ? minimo.minimo : null,
    valor_sem_minimo: minimo ? minimo.semMinimo : null,
    };
  });

  const { error: quoteItemsError } = await supabase.from("quote_items").insert(quoteItems);
  if (quoteItemsError) {
    await supabase.from("quotes").delete().eq("id", quoteId);
    return NextResponse.json({ error: quoteItemsError.message }, { status: 400 });
  }

  const { data: approveResult, error: approveError } = await supabase.rpc("approve_quote_and_generate_order", { p_quote_id: quoteId });
  if (approveError) {
    return NextResponse.json({ error: approveError.message }, { status: 400 });
  }
  const orderId = (approveResult as { order_id?: string } | null)?.order_id;
  if (!orderId) {
    return NextResponse.json({ error: "Não foi possível identificar o pedido gerado." }, { status: 400 });
  }

  await supabase
    .from("orders")
    .update({ internal_notes: internalNotes })
    .eq("id", orderId)
    .in("user_id", tenantIds);

  const { error: updateCatalogError } = await supabase
    .from("catalog_orders")
    .update({
      status: "approved",
      approved_order_id: orderId,
      approved_at: now,
      approved_by: user.id,
      updated_at: now,
    })
    .eq("id", catalogOrderId)
    .in("user_id", tenantIds);

  if (updateCatalogError) return NextResponse.json({ error: updateCatalogError.message }, { status: 400 });
  return NextResponse.json({ ok: true, order_id: orderId });
}
