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,
  };
}

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 String(activeExisting.id);

  const now = new Date().toISOString();
  const { data: created, error: createError } = await supabase
    .from("clients")
    .insert([
      {
        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,
      },
    ])
    .select("id")
    .single();

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

export async function POST(_req: Request, ctx: { params: Promise<{ id: string }> }) {
  const params = await ctx.params;
  const catalogOrderId = params.id;
  const supabase = await createClient();
  const {
    data: { user },
  } = await supabase.auth.getUser();
  if (!user) return NextResponse.json({ error: "Não autenticado." }, { status: 401 });

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

  const tenantIds = (companyCtx.tenantIds?.length ? companyCtx.tenantIds : [user.id]).filter((id): id is string => typeof id === "string" && id.length > 0);

  const { data: catalogOrderRow, error: catalogOrderError } = await supabase
    .from("catalog_orders")
    .select("id,user_id,number,status,kind,client_id,customer_name,customer_whatsapp,notes,currency,subtotal,discount,total,cart_payload,quote_id,catalog_order_items(id,product_id,title,description,quantity,unit_type,width_m,height_m,length_m,unit_price,selected_options,raw_item)")
    .eq("id", catalogOrderId)
    .in("user_id", tenantIds)
    .maybeSingle();

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

  const catalogOrder = catalogOrderRow as {
    id: string;
    user_id: string;
    number: number;
    status: "pending" | "approved" | "canceled";
    kind?: "order" | "quote_request" | null;
    client_id: string | null;
    notes: string | null;
    currency: string | null;
    subtotal: number | null;
    discount: number | null;
    total: number | null;
    quote_id: string | null;
    catalog_order_items: Array<{
      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;
      selected_options?: Record<string, unknown> | null;
      raw_item?: { valor_minimo_aplicado?: number | string | null; valor_sem_minimo?: number | string | null } | null;
    }> | null;
  };

  if (catalogOrder.quote_id) {
    const { data: quoteRow } = await supabase
      .from("quotes")
      .select("id,user_id")
      .eq("id", catalogOrder.quote_id)
      .in("user_id", tenantIds)
      .maybeSingle();
    if (quoteRow?.id) {
      return NextResponse.json({ ok: true, quote_id: quoteRow.id });
    }
  }

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

  let clientId = catalogOrder.client_id;
  if (clientId) {
    const { data: clientRow } = await supabase
      .from("clients")
      .select("id,is_deleted")
      .eq("id", clientId)
      .in("user_id", tenantIds)
      .maybeSingle();
    if (!clientRow || (clientRow as { is_deleted?: boolean | null }).is_deleted) clientId = null;
  }
  if (!clientId) {
    try {
      clientId = await ensureCatalogPlaceholderClient(supabase, catalogOrder.user_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 nextNumber = Math.max(1, Number((maxQuote as { number?: number } | null)?.number || 0) + 1);
  const now = new Date().toISOString();
  const shippingSnapshot = extractCatalogOrderShipping((catalogOrderRow as { cart_payload?: unknown } | null)?.cart_payload);
  const internalNotes = `origem:catalogo\ncatalog_order_id:${catalogOrder.id}`;

  const { data: createdQuote, error: createQuoteError } = await supabase
    .from("quotes")
    .insert([
      {
        user_id: catalogOrder.user_id,
        client_id: clientId,
        number: nextNumber,
        status: "draft",
        /* O pedido de orçamento chega com os preços do cadastro, que o cliente
           não viu: o título avisa quem vai revisar antes de mandar. */
        title:
          catalogOrder.kind === "quote_request"
            ? `Pedido de orçamento #${catalogOrder.number}`
            : `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 (createQuoteError || !createdQuote?.id) {
    return NextResponse.json({ error: createQuoteError?.message || "Não foi possível criar orçamento do catálogo." }, { status: 400 });
  }

  const quoteId = String(createdQuote.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).in("user_id", tenantIds);
      return NextResponse.json({ error: productsError.message }, { status: 400 });
    }

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

  const quoteItemsPayload = 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: Math.max(0, Number(item.quantity || 0)),
    unit_price: Math.max(0, 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 : Math.max(0, Number(item.unit_price || 0)) * Math.max(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(quoteItemsPayload);
  if (quoteItemsError) {
    await supabase.from("quotes").delete().eq("id", quoteId).in("user_id", tenantIds);
    return NextResponse.json({ error: quoteItemsError.message }, { status: 400 });
  }

  const { error: updateCatalogError } = await supabase
    .from("catalog_orders")
    .update({
      quote_id: quoteId,
      updated_at: now,
    })
    .eq("id", catalogOrder.id)
    .in("user_id", tenantIds);

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