import type { SupabaseClient, User } from "@supabase/supabase-js";
import { canCompany, getCompanyContext } from "@/lib/company-context";
import { ApiV1Error } from "@/lib/api-v1/errors";

function normalizePage(value: string | null, fallback: number) {
  const parsed = Number(value);
  if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
  return Math.floor(parsed);
}

function mapProduct(row: any) {
  return {
    id: String(row.id),
    name: String(row.name || ""),
    description: String(row.description || ""),
    price: Number(row.price || 0),
    category_id: row.category_id ? String(row.category_id) : null,
    category: row.categories
      ? {
          id: String(row.categories.id || ""),
          name: String(row.categories.name || ""),
          slug: String(row.categories.slug || ""),
        }
      : null,
    active: row.active !== false,
    image_url: row.image_url ? String(row.image_url) : null,
    images: Array.isArray(row.product_images)
      ? row.product_images.map((image: any) => ({
          image_url: image?.image_url ? String(image.image_url) : "",
          sort_order: Number(image?.sort_order || 0),
        }))
      : [],
    mockups: [],
    files: [],
  };
}

async function resolveProductReadContext(params: { supabase: SupabaseClient; user: User }) {
  const ctx = await getCompanyContext(params.supabase, params.user);
  if (!canCompany(ctx, params.user.id, "products.read")) {
    throw new ApiV1Error(403, "forbidden", "Sem permissao para visualizar produtos.");
  }

  return {
    ctx,
    tenantIds: ctx.tenantIds?.length ? ctx.tenantIds : [params.user.id],
  };
}

export async function listProducts(params: { supabase: SupabaseClient; user: User; request: Request }) {
  const { tenantIds } = await resolveProductReadContext(params);
  const { searchParams } = new URL(params.request.url);
  const q = (searchParams.get("q") || "").trim();
  const categoryId = (searchParams.get("category") || "").trim();
  const status = (searchParams.get("status") || "all").trim().toLowerCase();
  const page = normalizePage(searchParams.get("page"), 1);
  const perPage = Math.min(normalizePage(searchParams.get("per_page"), 20), 100);
  const from = (page - 1) * perPage;
  const to = from + perPage - 1;

  let query = params.supabase
    .from("products")
    .select("*, product_images(image_url, sort_order), categories(id,name,slug)", { count: "exact" })
    .in("user_id", tenantIds)
    .neq("product_kind", "digital")
    .order("name")
    .range(from, to);

  if (q) query = query.ilike("name", `%${q}%`);
  if (categoryId) query = query.eq("category_id", categoryId);
  if (status === "active") query = query.eq("active", true);
  if (status === "inactive") query = query.eq("active", false);

  const { data, error, count } = await query;
  if (error) throw new ApiV1Error(400, "products_fetch_failed", error.message);

  const products = (data || []).map((row: any) => mapProduct(row));

  return {
    ok: true,
    data: products,
    pagination: {
      page,
      per_page: perPage,
      total: count || 0,
    },
  };
}

export async function getProductById(params: { supabase: SupabaseClient; user: User; id: string }) {
  const { tenantIds } = await resolveProductReadContext(params);
  const { data, error } = await params.supabase
    .from("products")
    .select("*, product_images(image_url, sort_order), categories(id,name,slug)")
    .eq("id", params.id)
    .in("user_id", tenantIds)
    .maybeSingle();

  if (error) throw new ApiV1Error(400, "product_fetch_failed", error.message);
  if (!data) throw new ApiV1Error(404, "product_not_found", "Produto nao encontrado.");

  return {
    ok: true,
    data: mapProduct(data as any),
  };
}

export async function listProductsByIds(params: { supabase: SupabaseClient; user: User; ids: string[] }) {
  const { tenantIds } = await resolveProductReadContext(params);
  const ids = Array.from(new Set(params.ids.filter(Boolean)));

  if (!ids.length) {
    return {
      ok: true,
      data: [] as ReturnType<typeof mapProduct>[],
    };
  }

  const { data, error } = await params.supabase
    .from("products")
    .select("*, product_images(image_url, sort_order), categories(id,name,slug)")
    .in("id", ids)
    .in("user_id", tenantIds);

  if (error) throw new ApiV1Error(400, "products_fetch_failed", error.message);

  const mapped = ((data || []) as any[]).map((row) => mapProduct(row));
  const orderMap = new Map(ids.map((id, index) => [id, index]));
  mapped.sort((a, b) => (orderMap.get(a.id) ?? 0) - (orderMap.get(b.id) ?? 0));

  return {
    ok: true,
    data: mapped,
  };
}

export async function listFeaturedProducts(params: { supabase: SupabaseClient; user: User; limit?: number }) {
  const { tenantIds } = await resolveProductReadContext(params);
  const limit = Math.min(Math.max(params.limit || 6, 1), 20);

  const { data, error } = await params.supabase
    .from("products")
    .select("*, product_images(image_url, sort_order), categories(id,name,slug)")
    .in("user_id", tenantIds)
    .neq("product_kind", "digital")
    .eq("active", true)
    .order("name", { ascending: true })
    .limit(limit);

  if (error) throw new ApiV1Error(400, "products_fetch_failed", error.message);

  return {
    ok: true,
    data: ((data || []) as any[]).map((row) => mapProduct(row)),
  };
}
