import { NextResponse } from "next/server";
import { canCompany, getCompanyContext } from "@/lib/company-context";
import { createAdminClient, createClient } from "@/lib/supabase-server";
import { minutosDoPedido, separacaoDoPedido } from "@/lib/orders/ficha-de-producao";
import { montarFichasDoPedido, type ItemDoPedidoParaFicha } from "@/lib/orders/ficha-do-pedido.server";
import type { ProductionSheetPayload } from "@/lib/orders/production-sheet-print";

/**
 * A ordem de produção de um pedido.
 *
 * Documento interno: diz o que separar, o que fazer, em que ordem e quanto
 * tempo leva. Não carrega valor comercial nenhum — a produção não precisa
 * saber quanto o cliente pagou, e uma ficha que circula na oficina não é
 * lugar para isso.
 *
 * A receita de cada item vem de `montarFichasDoPedido`: a congelada na venda
 * quando existe, o cadastro atual quando não. As artes vêm do orçamento de
 * origem, casadas por assinatura do item.
 */

type OrderRow = {
  id: string;
  number: number;
  created_at: string;
  status: string;
  notes: string | null;
  internal_notes: string | null;
  quote_id: string | null;
  production_started_at?: string | null;
  production_accumulated_seconds?: number | null;
  production_last_stopped_at?: string | null;
  user_id: string;
  clients?: ClientRow | ClientRow[] | null;
  quotes?: QuoteMetaRow | QuoteMetaRow[] | null;
};

type ClientRow = { name?: string | null; company_name?: string | null };
type QuoteMetaRow = { title?: string | null; delivery_date?: string | null };

type QuoteItemRow = {
  id: string;
  product_id: string | null;
  title: string | null;
  description: string | null;
  quantity: number | string | null;
  unit_type: string | null;
  width_m: number | string | null;
  height_m: number | string | null;
  length_m: number | string | null;
};

type QuoteItemArtRow = {
  quote_item_id: string;
  image_urls: string[] | null;
};

function asFirst<T>(value: T | T[] | null | undefined): T | null {
  if (!value) return null;
  return Array.isArray(value) ? value[0] ?? null : value;
}

function addToMap<T>(map: Map<string, T[]>, key: string, value: T) {
  const list = map.get(key);
  if (list) {
    list.push(value);
    return;
  }
  map.set(key, [value]);
}

function signatureFromItem(item: {
  product_id?: string | null;
  title?: string | null;
  description?: string | null;
  quantity?: number | string | null;
  unit_type?: string | null;
  width_m?: number | string | null;
  height_m?: number | string | null;
  length_m?: number | string | null;
}) {
  const normalizedText = (value: string | null | undefined) => (value || "").trim().toLowerCase();
  const normalizedNumber = (value: number | string | null | undefined) => {
    const parsed = Number(value);
    return Number.isFinite(parsed) ? parsed.toFixed(6) : "0.000000";
  };
  return [
    item.product_id || "",
    normalizedText(item.title),
    normalizedText(item.description),
    normalizedText(item.unit_type),
    normalizedNumber(item.quantity),
    normalizedNumber(item.width_m),
    normalizedNumber(item.height_m),
    normalizedNumber(item.length_m),
  ].join("|");
}

export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
  try {
    const { id } = await params;
    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, "orders.read")) {
      return NextResponse.json({ error: "Sem permissão para visualizar pedidos." }, { status: 403 });
    }

    const tenantIds = companyCtx.tenantIds?.length ? companyCtx.tenantIds : [user.id];

    const { data: rawOrder, error: orderError } = await supabase
      .from("orders")
      .select(
        "id, number, created_at, status, notes, internal_notes, quote_id, production_started_at, production_accumulated_seconds, production_last_stopped_at, user_id, clients(name, company_name), quotes(title, delivery_date)"
      )
      .eq("id", id)
      .in("user_id", tenantIds)
      .maybeSingle();

    if (orderError) {
      return NextResponse.json({ error: orderError.message }, { status: 400 });
    }

    const order = rawOrder as OrderRow | null;
    if (!order) {
      return NextResponse.json({ error: "Pedido não encontrado." }, { status: 404 });
    }

    const { data: profileData } = await supabase
      .from("profiles")
      .select("catalog_name, store_name, logo_url, catalog_logo_url")
      .eq("id", order.user_id)
      .maybeSingle();

    const { data: itemsData, error: itemsError } = await supabase
      .from("order_items")
      .select(
        "id, order_id, product_id, title, description, quantity, unit_type, width_m, height_m, length_m, selected_options, production_snapshot, production_minutes, production_plan, products(sku, barcode, production_templates)"
      )
      .eq("order_id", id)
      .order("created_at", { ascending: true });

    if (itemsError) {
      return NextResponse.json({ error: itemsError.message }, { status: 400 });
    }

    const items = (itemsData || []) as unknown as ItemDoPedidoParaFicha[];
    const quoteMeta = asFirst(order.quotes);

    const { fichas, error: fichasError } = await montarFichasDoPedido(createAdminClient(), items, tenantIds);
    if (fichasError) {
      return NextResponse.json({ error: fichasError }, { status: 400 });
    }
    const fichaPorItem = new Map(fichas.map((f) => [f.itemId, f]));

    const artImagesByQuoteItem = new Map<string, string[]>();
    const quoteItemIdsBySignature = new Map<string, string[]>();
    const quoteItemIdsByPosition: string[] = [];

    if (order.quote_id) {
      const { data: quoteItemsData } = await supabase
        .from("quote_items")
        .select("id, product_id, title, description, quantity, unit_type, width_m, height_m, length_m")
        .eq("quote_id", order.quote_id)
        .order("position", { ascending: true });

      const { data: quoteArtsData } = await supabase
        .from("quote_item_arts")
        .select("quote_item_id, image_urls")
        .eq("quote_id", order.quote_id);

      ((quoteArtsData || []) as QuoteItemArtRow[]).forEach((artRow) => {
        artImagesByQuoteItem.set(
          artRow.quote_item_id,
          Array.isArray(artRow.image_urls) ? artRow.image_urls.filter(Boolean) : []
        );
      });

      ((quoteItemsData || []) as QuoteItemRow[]).forEach((quoteItem) => {
        quoteItemIdsByPosition.push(quoteItem.id);
        const signature = signatureFromItem(quoteItem);
        addToMap(quoteItemIdsBySignature, signature, quoteItem.id);
      });
    }

    const usedQuoteItemIds = new Set<string>();

    const payloadItems = items.map((item, index) => {
      const signature = signatureFromItem(item);
      const candidateIds = quoteItemIdsBySignature.get(signature) || [];
      let matchedQuoteItemId: string | null = null;

      while (candidateIds.length > 0 && !matchedQuoteItemId) {
        const candidateId = candidateIds.shift() || null;
        if (candidateId && !usedQuoteItemIds.has(candidateId)) {
          matchedQuoteItemId = candidateId;
        }
      }

      if (!matchedQuoteItemId) {
        const fallbackFromPosition = quoteItemIdsByPosition[index];
        if (fallbackFromPosition && !usedQuoteItemIds.has(fallbackFromPosition)) {
          matchedQuoteItemId = fallbackFromPosition;
        }
      }

      if (!matchedQuoteItemId) {
        matchedQuoteItemId = quoteItemIdsByPosition.find((quoteItemId) => !usedQuoteItemIds.has(quoteItemId)) || null;
      }

      if (matchedQuoteItemId) {
        usedQuoteItemIds.add(matchedQuoteItemId);
      }

      const montada = fichaPorItem.get(item.id);
      const ficha = montada?.ficha;

      return {
        id: item.id,
        title: item.title,
        description: item.description,
        quantity: item.quantity,
        unit_type: item.unit_type,
        width_m: item.width_m,
        height_m: item.height_m,
        length_m: item.length_m,
        sku: item.products?.sku || null,
        barcode: item.products?.barcode || null,
        tem_produto: Boolean(item.product_id),
        variacoes: (montada?.variacoes || []).map((v) => ({ atributo: v.atributo, valor: v.valor })),
        insumos: ficha?.insumos || [],
        processos: ficha?.processos || [],
        minutos_totais: ficha?.minutosTotais || 0,
        avisos: montada?.avisos || [],
        receita_de: montada?.receitaDe || "nenhuma",
        receita_em: montada?.receitaEm || null,
        gabaritos: montada?.gabaritos || [],
        art_images: matchedQuoteItemId ? artImagesByQuoteItem.get(matchedQuoteItemId) || [] : [],
      };
    });

    const todasAsFichas = fichas.map((f) => f.ficha);

    const payload: ProductionSheetPayload = {
      order: {
        id: order.id,
        number: order.number,
        created_at: order.created_at,
        status: order.status,
        notes: order.notes,
        internal_notes: order.internal_notes,
        quote_title: quoteMeta?.title || null,
        delivery_date: quoteMeta?.delivery_date || null,
        production_started_at: order.production_started_at || null,
        production_accumulated_seconds: Number(order.production_accumulated_seconds || 0),
        production_last_stopped_at: order.production_last_stopped_at || null,
        minutos_previstos: minutosDoPedido(todasAsFichas),
      },
      company: {
        catalog_name: profileData?.catalog_name || null,
        store_name: profileData?.store_name || null,
        logo_url: profileData?.logo_url || null,
        catalog_logo_url: profileData?.catalog_logo_url || null,
      },
      client: (() => {
        const client = asFirst(order.clients);
        return client ? { name: client.name || null, company_name: client.company_name || null } : null;
      })(),
      items: payloadItems,
      separacao: separacaoDoPedido(todasAsFichas),
    };

    return NextResponse.json(payload);
  } catch (error) {
    const message = error instanceof Error ? error.message : "Erro interno ao gerar a ordem de produção.";
    return NextResponse.json({ error: message }, { status: 500 });
  }
}
