import Link from "next/link";
import type { ReactNode } from "react";
import { ArrowLeft, MapPin, Pencil } from "lucide-react";
import { addressLookupApi } from "@/lib/api/addressLookup";
import { sellerApi } from "@/lib/api/seller";
import { requireRole, requireServerToken } from "@/lib/auth/server";
import type {
  ApiProductAttributes,
  ApiSellerForPrice,
  ApiSellerProductDetail,
} from "@/lib/api/types";
import SafeImage from "@/components/ui/SafeImage";
import ForPriceForm from "./ForPriceForm";
import PriceVisibilityForm from "./PriceVisibilityForm";
import StatusToggle from "./StatusToggle";
import UpdateButton from "./updates/UpdateButton";
import { formatValidity, inr } from "../format";
import { formatUnit } from "@/lib/utils";

type PageProps = {
  params: Promise<{ id: string }>;
};

async function loadProduct(token: string, id: number) {
  try {
    return await sellerApi.product(token, id);
  } catch {
    return null as ApiSellerProductDetail | null;
  }
}

/**
 * The variation, quality and stock panels all read from the catalog rows behind
 * the product. Fetched here rather than when a dialog opens, so the forms are
 * already seeded when the seller clicks — and so a failure degrades to empty
 * panels rather than an error boundary over the whole page.
 */
async function loadAttributes(token: string, id: number): Promise<ApiProductAttributes> {
  try {
    return await sellerApi.productAttributes(token, id);
  } catch {
    return { variants: [], qualities: [] };
  }
}

/**
 * The city F.O.R panel's data: the prices already quoted, and the state list to
 * pick from.
 *
 * States come from the `addresses` lookup, grouped so a state appears once
 * however many pincodes it covers. Cities follow the chosen state and are
 * fetched in the browser — 716 of them across 37 states is not worth shipping
 * up front.
 */
async function loadForPrices(token: string, id: number) {
  const [prices, states] = await Promise.all([
    sellerApi.productForPrices(token, id).then((r) => r.data ?? []).catch(() => [] as ApiSellerForPrice[]),
    addressLookupApi.states().catch(() => [] as string[]),
  ]);

  return { prices, states };
}

/* ------------------------------------------------------------------ */
/* Layout primitives                                                   */
/* ------------------------------------------------------------------ */

function Card({
  title,
  subtitle,
  action,
  children,
  className,
}: {
  title?: string;
  subtitle?: string;
  /** Sits on the right of the header — the card's own update action. */
  action?: ReactNode;
  children: ReactNode;
  className?: string;
}) {
  return (
    <section className={`rounded-xl bg-white p-5 shadow-sm ring-1 ring-gray-100 ${className ?? ""}`}>
      {title ? (
        <div className="mb-4 flex items-start justify-between gap-3">
          <div className="min-w-0">
            <h2 className="text-sm font-semibold text-gray-900">{title}</h2>
            {subtitle ? <p className="mt-0.5 text-xs text-gray-500">{subtitle}</p> : null}
          </div>
          {action ? <div className="flex shrink-0 flex-wrap justify-end gap-2">{action}</div> : null}
        </div>
      ) : null}
      {children}
    </section>
  );
}

function Fact({ label, children }: { label: string; children: ReactNode }) {
  return (
    <div>
      <dt className="text-xs text-gray-500">{label}</dt>
      <dd className="mt-0.5 font-medium text-gray-900">{children}</dd>
    </div>
  );
}

/** One line of the ex-price build-up. */
function PriceLine({
  label,
  amount,
  muted,
}: {
  label: string;
  amount: number;
  muted?: boolean;
}) {
  return (
    <div className="flex items-baseline justify-between gap-3 text-sm">
      <span className={muted ? "text-gray-500" : "text-gray-700"}>{label}</span>
      <span className={`tabular-nums ${muted ? "text-gray-500" : "text-gray-900"}`}>
        {inr.format(amount)}
      </span>
    </div>
  );
}

function Pill({ children, tone }: { children: ReactNode; tone: "on" | "off" }) {
  return (
    <span
      className={`inline-flex rounded-full px-2 py-0.5 text-[11px] font-medium ring-1 ring-inset ${
        tone === "on"
          ? "bg-emerald-50 text-emerald-700 ring-emerald-200"
          : "bg-gray-50 text-gray-500 ring-gray-200"
      }`}
    >
      {children}
    </span>
  );
}

/**
 * Server-rendered detail view. `requireServerToken` reads the auth cookie during
 * SSR, so the product is fetched before the response is sent instead of after
 * `useToken` resolves in an effect — which is what forced the old spinner.
 *
 * `RequireRole` is replaced by a server-side check on the same cached user
 * cookie it consulted: the client guard could only redirect after hydration, and
 * until then it rendered a loader over content the server already had.
 */
export default async function SellerProductDetailPage({ params }: PageProps) {
  const { id } = await params;
  const path = `/seller/products/${id}`;

  const token = await requireServerToken(path);
  await requireRole(["seller"]);

  const product = await loadProduct(token, Number(id));

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

  const underReview = product.request_status === "pending_review";
  // Admin grants each price panel per seller, off by default, so there is
  // nothing to fetch for one until its own grant is there.
  const canManageForPrice = product.can_manage_for_price === true;
  const [attributes, forPrices] = await Promise.all([
    underReview
      ? Promise.resolve({ variants: [], qualities: [] } as ApiProductAttributes)
      : loadAttributes(token, product.id),
    canManageForPrice
      ? loadForPrices(token, product.id)
      : Promise.resolve({ prices: [] as ApiSellerForPrice[], states: [] as string[] }),
  ]);

  const { charges, price_breakup: breakup } = product;
  const soldVariants = attributes.variants.filter((v) => v.is_selected);
  const soldQualities = attributes.qualities.filter((q) => q.is_selected);
  const hasSpecs =
    product.specifications.physical.length > 0 || product.specifications.chemical.length > 0;
  const hasWizardDetails = Boolean(
    product.hsn_code || product.product_type || product.net_weight || product.moq || product.make
  );

  return (
    <div className="space-y-4">
      <Link href="/seller/products" className="inline-flex items-center gap-1 text-sm text-gray-600 hover:text-[#CC1414]">
        <ArrowLeft className="h-4 w-4" /> Back to products
      </Link>

      <div className="grid grid-cols-1 gap-4 lg:grid-cols-3">
        <Card className="lg:col-span-1">
          <div className="relative aspect-square overflow-hidden rounded-lg bg-gray-100">
            <SafeImage
              src={product.thumbnail || "/logo.png"}
              alt={product.name}
              fill
              sizes="(min-width: 1024px) 33vw, 100vw"
              className="object-cover"
            />
          </div>
          {product.images.length > 1 && (
            <div className="mt-2 grid grid-cols-4 gap-2">
              {product.images.slice(0, 8).map((src, i) => (
                <div key={i} className="relative aspect-square w-full overflow-hidden rounded-md ring-1 ring-gray-100">
                  <SafeImage src={src || "/logo.png"} alt="" fill sizes="64px" className="object-cover" />
                </div>
              ))}
            </div>
          )}
        </Card>

        <div className="space-y-4 lg:col-span-2">
          <Card>
            <div className="flex flex-wrap items-start justify-between gap-4">
              <div className="min-w-0">
                <h1 className="text-xl font-bold text-gray-900">{product.name}</h1>
                <p className="mt-0.5 text-sm text-gray-500">
                  {product.brand?.name ?? product.brand_name ?? "—"}
                  {product.category?.name ? ` · ${product.category.name}` : ""}
                  {product.unit?.name ? ` · ${product.unit.name}` : ""}
                </p>
                <div className="mt-2 flex flex-wrap items-center gap-2">
                  <Pill tone={product.request_status === "approved" ? "on" : "off"}>
                    {(product.request_status ?? "draft").replace("_", " ")}
                  </Pill>
                  {product.request_status === "approved" && (
                    <Pill tone={product.status === "active" ? "on" : "off"}>{product.status}</Pill>
                  )}
                  {product.request_reference && (
                    <span className="font-mono text-[11px] text-gray-400">{product.request_reference}</span>
                  )}
                </div>
              </div>
              <div className="flex shrink-0 flex-wrap items-center gap-2">
                {/* The wizard, prefilled — the seller can jump to any step and
                    save just that step's data. */}
                {product.can_edit && (
                  <Link
                    href={`/seller/products/${product.id}/edit`}
                    className="inline-flex items-center gap-1.5 rounded-lg border border-gray-200 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:border-[#CC1414] hover:text-[#CC1414]"
                  >
                    <Pencil className="h-4 w-4" />
                    {product.request_status === "rejected" ? "Edit & Resubmit" : "Edit"}
                  </Link>
                )}
                {/* Only approved (live) products can be toggled active/inactive. */}
                {product.request_status === "approved" && (
                  <StatusToggle id={product.id} active={product.status === "active"} />
                )}
              </div>
            </div>

            {product.short_description && (
              <p className="mt-3 text-sm text-gray-600">{product.short_description}</p>
            )}

            {product.request_status !== "approved" && (
              <div
                className={`mt-4 rounded-lg border p-3 text-sm ${
                  product.request_status === "rejected"
                    ? "border-red-200 bg-red-50 text-red-700"
                    : "border-amber-200 bg-amber-50 text-amber-800"
                }`}
              >
                {underReview && (
                  <p>This product is under review. You can’t activate it until it’s approved.</p>
                )}
                {product.request_status === "rejected" && (
                  <>
                    <p className="font-semibold">This product was rejected.</p>
                    {product.review_note ? <p className="mt-1">Reason: {product.review_note}</p> : null}
                    <p className="mt-1">Edit the details and resubmit for review.</p>
                  </>
                )}
                {product.request_status === "draft" && (
                  <p>This product is a draft. Complete and submit it for review.</p>
                )}
              </div>
            )}
          </Card>

          {/* The ex price is what buyers compare on, so it leads — with every
              component that produced it spelled out underneath. */}
          <Card
            title="Pricing"
            subtitle="Ex-Works — the price buyers compare on"
            action={
              !underReview && (
                <UpdateButton panel="price" product={product} attributes={attributes} />
              )
            }
          >
            <div className="rounded-lg bg-gray-50 p-4">
              <div className="flex items-baseline justify-between gap-3">
                <span className="text-xs font-medium text-gray-500">Ex Price</span>
                <span className="text-2xl font-black tabular-nums text-[#CC1414]">
                  {product.ex_price ? inr.format(product.ex_price) : "—"}
                  {product.unit?.name && (
                    <span className="ml-1 text-xs font-medium text-gray-400">/ {formatUnit(product.unit.name)}</span>
                  )}
                </span>
              </div>
            </div>

            <div className="mt-4 space-y-2">
              <PriceLine label="Base price" amount={breakup.base_price} />
              {breakup.gauge_diff !== 0 && (
                <PriceLine label="Gauge difference" amount={breakup.gauge_diff} />
              )}
              {charges.loading !== 0 && <PriceLine label="Loading charge" amount={charges.loading} muted />}
              {charges.insurance !== 0 && (
                <PriceLine label="Insurance charge" amount={charges.insurance} muted />
              )}
              {charges.quality !== 0 && <PriceLine label="Quality charge" amount={charges.quality} muted />}
              {charges.other.map((charge, i) => (
                <PriceLine
                  key={i}
                  label={`${charge.name}${charge.operator === "-" ? " (deducted)" : ""}`}
                  amount={charge.operator === "-" ? -charge.price : charge.price}
                  muted
                />
              ))}
              {/* Every line above sums to this; GST is charged on it (B41). */}
              <div className="border-t border-dashed border-gray-200 pt-2">
                <PriceLine
                  label="Taxable value"
                  amount={breakup.taxable ?? breakup.base_price + breakup.gauge_diff + breakup.total_charges}
                />
              </div>
              {/* Always shown: a 0% slab is still a GST line, with its rate. */}
              <PriceLine label={`GST @ ${breakup.gst}%`} amount={breakup.tax_amount} muted />
              <div className="border-t border-gray-100 pt-2">
                <PriceLine label="Ex Price" amount={product.ex_price} />
              </div>
              {charges.tcs !== 0 && (
                <p className="text-xs text-gray-500">TCS {charges.tcs}% is applied at invoicing.</p>
              )}
            </div>
          </Card>

          <Card title="Availability">
            <dl className="grid grid-cols-2 gap-4 text-sm sm:grid-cols-4">
              <Fact label="Quantity">{product.quantity || "—"}</Fact>
              <Fact label="Dispatch Within">
                {product.load_within ? `${product.load_within} days` : "—"}
              </Fact>
              <Fact label="MOQ">
                {product.moq ? `${product.moq} ${product.moq_unit ?? ""}`.trim() : "—"}
              </Fact>
              <Fact label="Price Validity">{formatValidity(product.price_validity)}</Fact>
            </dl>
          </Card>
        </div>
      </div>

      {/* Which of the three prices this listing publishes. Sits above the F.O.R
          panel because it decides whether anything quoted there reaches a
          buyer at all. Piloted with one seller, so the API says who gets it
          rather than this page deciding. */}
      {product.can_manage_price_visibility && (
        <Card
          title="Price Visibility"
          subtitle="What buyers see on the public product page"
        >
          <PriceVisibilityForm
            productId={product.id}
            slug={product.slug}
            showExPrice={product.show_ex_price}
            showForPrice={product.show_for_price}
            showBasicPrice={product.show_basic_price ?? false}
            showFobPrice={product.show_fob_price}
          />
        </Card>
      )}

      {/* F.O.R is the delivered price, so it is per destination rather than one
          number on the product — a city quoted here replaces the calculated
          Ex Price + freight for buyers there. Because that override applies to
          every buyer in the city, admin turns the panel on per seller; without
          the grant the card is not rendered at all. F.O.B has its own grant
          (`can_manage_fob_price`) for the card it will get. */}
      {canManageForPrice && (
        <Card
          title="F.O.R Prices by City"
          subtitle="Your freight to each city — Ex Price + freight is the F.O.R price buyers there see"
        >
          <ForPriceForm
            productId={product.id}
            slug={product.slug}
            exPrice={product.ex_price}
            states={forPrices.states}
            prices={forPrices.prices}
          />
        </Card>
      )}

      {(attributes.variants.length > 0 || attributes.qualities.length > 0) && (
        <div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
          {attributes.variants.length > 0 && (
            <Card
              title="Variations"
              subtitle={`${soldVariants.length} of ${attributes.variants.length} offered`}
              // action={
              //   <>
              //     <UpdateButton panel="variation" product={product} attributes={attributes} />
              //     <UpdateButton
              //       panel="stock"
              //       product={product}
              //       attributes={attributes}
              //       variant="ghost"
              //     />
              //   </>
              // }
            >
              <div className="overflow-x-auto">
                <table className="w-full min-w-[360px] text-sm">
                  <thead>
                    <tr className="border-b border-gray-200 text-left text-xs font-medium text-gray-500">
                      <th className="pb-2 pr-3">Variation</th>
                      <th className="pb-2 pr-3 text-right">Difference</th>
                      <th className="pb-2 pr-3 text-right">Stock</th>
                      <th className="pb-2 text-right">Status</th>
                    </tr>
                  </thead>
                  <tbody>
                    {attributes.variants.map((v) => (
                      <tr key={v.id} className="border-b border-gray-50 last:border-0">
                        <td className="py-2 pr-3 font-medium text-gray-900">{v.label || "—"}</td>
                        <td className="py-2 pr-3 text-right tabular-nums text-gray-700">
                          {v.is_selected ? inr.format(Number(v.price) || 0) : "—"}
                        </td>
                        <td className="py-2 pr-3 text-right tabular-nums text-gray-700">
                          {v.is_selected ? v.stock || "—" : "—"}
                        </td>
                        <td className="py-2 text-right">
                          <Pill tone={v.is_selected ? "on" : "off"}>
                            {v.is_selected ? "Selling" : "Not sold"}
                          </Pill>
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            </Card>
          )}

          {attributes.qualities.length > 0 && (
            <Card
              title="Quality Grades"
              subtitle={`${soldQualities.length} of ${attributes.qualities.length} offered`}
              // action={<UpdateButton panel="quality" product={product} attributes={attributes} />}
            >
              <div className="overflow-x-auto">
                <table className="w-full min-w-[360px] text-sm">
                  <thead>
                    <tr className="border-b border-gray-200 text-left text-xs font-medium text-gray-500">
                      <th className="pb-2 pr-3">Grade</th>
                      <th className="pb-2 pr-3 text-right">Your price</th>
                      <th className="pb-2 pr-3 text-right">Catalog</th>
                      <th className="pb-2 text-right">Status</th>
                    </tr>
                  </thead>
                  <tbody>
                    {attributes.qualities.map((q) => (
                      <tr key={q.name} className="border-b border-gray-50 last:border-0">
                        <td className="py-2 pr-3 font-medium text-gray-900">{q.name}</td>
                        <td className="py-2 pr-3 text-right tabular-nums text-gray-700">
                          {q.is_selected ? inr.format(Number(q.price) || 0) : "—"}
                        </td>
                        <td className="py-2 pr-3 text-right tabular-nums text-gray-500">
                          {inr.format(Number(q.catalog_price) || 0)}
                        </td>
                        <td className="py-2 text-right">
                          <Pill tone={q.is_selected ? "on" : "off"}>
                            {q.is_selected ? "Selling" : "Not sold"}
                          </Pill>
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            </Card>
          )}
        </div>
      )}

      <div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
        {product.loading_addresses.length > 0 && (
          <Card title="Loading Points">
            <ul className="space-y-3 text-sm">
              {product.loading_addresses.map((addr, i) => (
                <li key={i} className="flex gap-2">
                  <MapPin className="mt-0.5 h-4 w-4 shrink-0 text-[#CC1414]" />
                  <div className="min-w-0 text-gray-700">
                    {addr.address_line_one && <p>{addr.address_line_one}</p>}
                    {addr.address_line_two && <p className="text-gray-500">{addr.address_line_two}</p>}
                    <p className="text-gray-500">
                      {[addr.city, addr.state, addr.pincode, addr.country].filter(Boolean).join(", ") || "—"}
                    </p>
                  </div>
                </li>
              ))}
            </ul>
          </Card>
        )}

        {product.packaging.length > 0 && (
          <Card title="Packaging">
            <ul className="space-y-2 text-sm">
              {product.packaging.map((pack) => (
                <li key={pack.id} className="flex items-baseline justify-between gap-3">
                  <span className="text-gray-700">{pack.name}</span>
                  <span className="tabular-nums text-gray-500">
                    {pack.charge ? inr.format(pack.charge) : "No extra charge"}
                  </span>
                </li>
              ))}
            </ul>
          </Card>
        )}
      </div>

      {hasWizardDetails && (
        <Card title="Product Details">
          <dl className="grid grid-cols-2 gap-4 text-sm sm:grid-cols-4">
            {product.product_type && (
              <Fact label="Type">{product.product_type.replace("_", " ")}</Fact>
            )}
            {product.hsn_code && <Fact label="HSN Code">{product.hsn_code}</Fact>}
            {product.net_weight && (
              <Fact label="Net Weight">
                {`${product.net_weight} ${product.weight_unit ?? ""}`.trim()}
              </Fact>
            )}
            {product.tolerance && <Fact label="Tolerance">{product.tolerance}</Fact>}
            {product.make && <Fact label="Make">{product.make}</Fact>}
            {product.tax_rate !== null && <Fact label="Tax Rate">{product.tax_rate}%</Fact>}
            <Fact label="Slug">
              <span className="font-mono text-xs text-gray-700">{product.slug ?? "—"}</span>
            </Fact>
          </dl>
          {product.description && (
            <p className="mt-4 whitespace-pre-line border-t border-gray-100 pt-4 text-sm text-gray-600">
              {product.description}
            </p>
          )}
        </Card>
      )}

      {hasSpecs && (
        <div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
          {(["physical", "chemical"] as const).map((kind) =>
            product.specifications[kind].length > 0 ? (
              <Card key={kind} title={`${kind === "physical" ? "Physical" : "Chemical"} Specifications`}>
                <dl className="space-y-2 text-sm">
                  {product.specifications[kind].map((row, i) => (
                    <div key={i} className="flex items-baseline justify-between gap-3">
                      <dt className="text-gray-500">{row.parameter}</dt>
                      <dd className="font-medium text-gray-900">{row.value}</dd>
                    </div>
                  ))}
                </dl>
              </Card>
            ) : null
          )}
        </div>
      )}

      {/* Operating data stays editable outside the wizard — but not while a
          reviewer is holding the product, which is what the API enforces too. */}
      {underReview && (
        <p className="rounded-xl bg-white p-5 text-xs text-gray-500 shadow-sm ring-1 ring-gray-100">
          Pricing, variations, quality and stock can be updated once this product has been reviewed.
        </p>
      )}
    </div>
  );
}
