import Link from "next/link";
import { ArrowLeft } from "lucide-react";
import { catalogApi } from "@/lib/api/catalog";
import { sellerApi } from "@/lib/api/seller";
import { requireRole, requireServerToken } from "@/lib/auth/server";
import type {
  ApiBrand,
  ApiCategory,
  ApiPackagingType,
  ApiProductEditData,
  ApiProductUnit,
  ApiSubCategory,
} from "@/lib/api/types";
import ProductWizard from "../../new/ProductWizard";
import { defaultProductValues, knownChargeTypes, type ProductFormValues } from "../../new/product.schema";

type ChargeRow = ProductFormValues["charges"][number];
type QualityRow = ProductFormValues["qualities"][number];
type VariantRow = ProductFormValues["variants"][number];

/** Map the backend edit payload's `data` block back into wizard form values. */
function mapToFormValues(data: Record<string, unknown>): Partial<ProductFormValues> {
  const asString = (v: unknown) => (v == null ? "" : String(v));
  const arr = <T,>(v: unknown, fallback: T[]): T[] =>
    Array.isArray(v) && v.length ? (v as T[]) : fallback;

  /*
    The API already returns every charge the form knows about — the four with a
    column of their own plus any extras — so the rows are taken as they come.
    Only the order is normalised, so Loading/Insurance/GST/TCS stay at the top
    even on a product that never had them set.
  */
  const savedCharges = Array.isArray(data.charges) ? (data.charges as ChargeRow[]) : [];
  const findCharge = (type: string) =>
    savedCharges.find((c) => (c.type ?? "").toLowerCase() === type.toLowerCase());

  const baseCharges: ChargeRow[] = knownChargeTypes.map(
    (known) =>
      findCharge(known.type) ?? { type: known.type, enabled: false, amount: "", operator: "+" as const }
  );
  const extraCharges = savedCharges.filter((c) => !knownChargeTypes.some((k) => k.type.toLowerCase() === (c.type ?? "").toLowerCase()));

  // Grades arrive already merged with the parent catalog's list, with
  // `is_selected` marking the ones this seller offers.
  const savedQualities = Array.isArray(data.qualities)
    ? (data.qualities as Array<{ name?: string; price?: string; is_selected?: boolean }>)
    : [];
  const qualities: QualityRow[] = savedQualities.map((row) => ({
    name: asString(row.name),
    price: asString(row.price),
    selected: Boolean(row.is_selected),
  }));

  // Catalog variations arrive already labelled ("8 MM") with `is_selected`; a
  // seller's own rows arrive with a size and unit and no id.
  const savedVariants = Array.isArray(data.variants)
    ? (data.variants as Array<Record<string, unknown>>)
    : [];
  const variants: VariantRow[] = savedVariants.map((row) => ({
    id: asString(row.id),
    label: asString(row.label),
    size: asString(row.size),
    unit: asString(row.unit),
    charge: asString(row.charge),
    stock: asString(row.stock),
    selected: row.is_selected === undefined ? true : Boolean(row.is_selected),
  }));

  return {
    product_name: asString(data.product_name),
    // Kept so re-saving step 1 does not drop the link to the catalog product
    // this listing was created from.
    commodity_product_id: asString(data.commodity_product_id),
    category: asString(data.category),
    sub_category: asString(data.sub_category),
    product_type: (asString(data.product_type) || "raw_material") as ProductFormValues["product_type"],
    short_description: asString(data.short_description),
    detailed_description: asString(data.detailed_description),
    hsn_code: asString(data.hsn_code),
    tax_rate: asString(data.tax_rate),
    product_video: asString(data.product_video),
    qualities: qualities.length ? qualities : defaultProductValues.qualities,
    quality_charge: asString(data.quality_charge),
    quality_description: asString(data.quality_description),
    packaging: arr(data.packaging, defaultProductValues.packaging),
    brand_id: asString(data.brand_id),
    make: asString(data.make),
    physical_specs: arr(data.physical_specs, defaultProductValues.physical_specs),
    chemical_specs: arr(data.chemical_specs, defaultProductValues.chemical_specs),
    weight_unit: asString(data.weight_unit),
    net_weight: asString(data.net_weight),
    tolerance: asString(data.tolerance),
    variants: variants.length ? variants : defaultProductValues.variants,
    loading_city: asString(data.loading_city),
    loading_state: asString(data.loading_state),
    country: asString(data.country) || "India",
    moq: asString(data.moq),
    moq_unit: asString(data.moq_unit),
    available_quantity: asString((data as { available_quantity?: unknown }).available_quantity),
    load_within: asString((data as { load_within?: unknown }).load_within),
    charges: [...baseCharges, ...extraCharges],
    publish_on: asString(data.publish_on),
    product_images: [],
  };
}

async function loadEditData(token: string, id: number) {
  try {
    const res = await sellerApi.productEditData(token, id);
    return res.data;
  } catch {
    return null as ApiProductEditData | null;
  }
}

/**
 * The dropdowns for step 1, fetched here rather than from an effect inside the
 * wizard.
 *
 * A `<select>` seeded by react-hook-form on mount silently falls back to blank
 * when its value matches no option yet — which is exactly what happened while
 * the category list was still in flight, leaving a saved Category and Sub
 * Category looking unset. Fetching them alongside the product means the options
 * are there for the first render.
 */
async function loadFormOptions(categoryId: string) {
  const [categories, subCategories, brands, packagingTypes, units] = await Promise.all([
    catalogApi.categories({ per_page: 100 }).then((r) => r.data ?? []).catch(() => [] as ApiCategory[]),
    categoryId
      ? catalogApi.subCategories(Number(categoryId)).then((r) => r.data ?? []).catch(() => [] as ApiSubCategory[])
      : Promise.resolve([] as ApiSubCategory[]),
    catalogApi.brands({ per_page: 100 }).then((r) => r.data ?? []).catch(() => [] as ApiBrand[]),
    catalogApi.packagingTypes().then((r) => r.data ?? []).catch(() => [] as ApiPackagingType[]),
    catalogApi.units().then((r) => r.data ?? []).catch(() => [] as ApiProductUnit[]),
  ]);

  return { categories, subCategories, brands, packagingTypes, units };
}

/**
 * Only the *loading* half became a Server Component. The wizard below is a real
 * multi-step form and stays on the client — but it no longer waits for the
 * browser to boot before the product it is editing exists: the fetch, the
 * permission check and the payload-to-form-values mapping all happen during SSR,
 * and the wizard receives its initial values as plain props.
 */
export default async function EditProductPage({
  params,
}: {
  params: Promise<{ id: string }>;
}) {
  const { id } = await params;
  const token = await requireServerToken(`/seller/products/${id}/edit`);
  await requireRole(["seller"]);

  const payload = await loadEditData(token, Number(id));

  if (!payload) {
    return <div className="rounded-xl bg-white p-10 text-center text-gray-500 shadow-sm ring-1 ring-gray-100">Product not found.</div>;
  }

  const values = mapToFormValues(payload.data);
  const { categories, subCategories, brands, packagingTypes, units } = await loadFormOptions(values.category ?? "");

  if (!payload.can_edit) {
    return (
      <div className="space-y-4">
        <Link href={`/seller/products/${id}`} className="inline-flex items-center gap-1 text-sm text-gray-600 hover:text-[#CC1414]">
          <ArrowLeft className="h-4 w-4" /> Back to product
        </Link>
        <div className="rounded-xl bg-white p-8 text-center shadow-sm ring-1 ring-gray-100">
          <p className="text-sm text-gray-700">
            This product is <span className="font-semibold">{payload.request_status.replace("_", " ")}</span> and cannot be edited right now.
          </p>
        </div>
      </div>
    );
  }

  return (
    <>
      {payload.request_status === "rejected" && payload.review_note ? (
        <div className="mb-4 rounded-xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-800">
          <p className="font-semibold">This product was rejected. Please fix and resubmit.</p>
          <p className="mt-1">Reason: {payload.review_note}</p>
        </div>
      ) : null}
      {payload.request_status === "approved" ? (
        <div className="mb-4 rounded-xl border border-emerald-200 bg-emerald-50 p-4 text-sm text-emerald-800">
          This product is live. Saving a step updates the listing immediately — it does not go back
          for review.
        </div>
      ) : null}
      <ProductWizard
        mode="edit"
        productId={payload.id}
        requestStatus={payload.request_status}
        initialValues={values}
        existingImages={payload.existing_images ?? []}
        initialCategories={categories}
        initialSubCategories={subCategories}
        initialBrands={brands}
        initialPackagingTypes={packagingTypes}
        initialUnits={units}
      />
    </>
  );
}
