import Link from "next/link";
import { prisma } from "@/lib/prisma";
import { PropertyCard } from "@/components/PropertyCard";
import { AreaTagInput } from "@/components/AreaTagInput";
import { LISTING_TYPE_LABELS, SELECTABLE_LISTING_TYPES } from "@/lib/labels";
import type { Prisma } from "@/generated/prisma/client";

function toArray(v: string | string[] | undefined): string[] {
  if (!v) return [];
  return Array.isArray(v) ? v : [v];
}

/** Monthly asking price for To Let, or the asking price for a sale — used by the price filter. */
function effectivePrice(p: {
  listingType: string;
  salePrice: number | null;
  monthlyRent: number | null;
  ratePerM2: number | null;
  sizeM2: number;
}) {
  if (p.listingType === "FOR_SALE") return p.salePrice;
  if (p.monthlyRent) return p.monthlyRent;
  if (p.ratePerM2) return p.ratePerM2 * p.sizeM2;
  return null;
}

const PRICE_STEPS = [10000, 25000, 50000, 100000, 250000, 500000, 1000000];
const SIZE_STEPS = [100, 200, 500, 1000, 2000, 5000];

const pillSelect = "w-full rounded-full border border-stone-300 bg-white px-4 py-2.5 text-sm font-medium text-stone-700";

export default async function PropertiesPage({
  searchParams,
}: {
  searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
}) {
  const sp = await searchParams;
  const listingType = typeof sp.listingType === "string" ? sp.listingType : "";
  const type = typeof sp.type === "string" ? sp.type : "";
  const selectedAreas = toArray(sp.area);
  const facilities = toArray(sp.facility);
  const region = typeof sp.region === "string" ? sp.region : undefined;
  const minSize = sp.minSize ? Number(sp.minSize) : 0;
  const minPrice = sp.minPrice ? Number(sp.minPrice) : 0;
  const maxPrice = sp.maxPrice ? Number(sp.maxPrice) : 0;
  const sort = typeof sp.sort === "string" ? sp.sort : "newest";

  const [amenities, areas] = await Promise.all([
    prisma.amenity.findMany({ orderBy: { name: "asc" } }),
    prisma.area.findMany({ orderBy: { name: "asc" } }),
  ]);

  const AND: Prisma.PropertyWhereInput[] = [];
  if (type) AND.push({ type: type as "OFFICE" | "INDUSTRIAL" | "RETAIL" });
  if (listingType) AND.push({ listingType: listingType as "TO_LET" | "FOR_SALE" });
  if (selectedAreas.length) AND.push({ area: { name: { in: selectedAreas } } });
  if (region) AND.push({ area: { region } });
  if (minSize) AND.push({ sizeM2: { gte: minSize } });
  for (const facilityId of facilities) {
    AND.push({ amenities: { some: { id: Number(facilityId) } } });
  }

  const orderBy: Prisma.PropertyOrderByWithRelationInput =
    sort === "price-asc"
      ? { monthlyRent: "asc" }
      : sort === "price-desc"
        ? { monthlyRent: "desc" }
        : sort === "size-desc"
          ? { sizeM2: "desc" }
          : { dateListed: "desc" };

  const found = await prisma.property.findMany({
    where: { status: { in: ["ACTIVE", "UNDER_OFFER"] }, AND },
    include: {
      area: true,
      broker: true,
      amenities: true,
      photos: { where: { isHero: true }, take: 1 },
      _count: { select: { photos: true } },
    },
    orderBy,
  });

  // Price spans rate-per-m², monthly rent and sale price, so it is normalised here rather than in SQL.
  const properties = found.filter((p) => {
    if (!minPrice && !maxPrice) return true;
    const price = effectivePrice(p);
    if (price === null) return false;
    if (minPrice && price < minPrice) return false;
    if (maxPrice && price > maxPrice) return false;
    return true;
  });

  const checkedFacilities = new Set(facilities);

  return (
    <main className="mx-auto max-w-6xl px-6 py-8">
      <form className="flex flex-col gap-2.5">
        <div className="flex flex-col gap-2.5 sm:flex-row">
          <select
            name="listingType"
            defaultValue={listingType}
            aria-label="Listing type"
            className="rounded-full border border-stone-300 bg-white px-4 py-2.5 text-sm font-medium text-stone-700 sm:w-52"
          >
            <option value="">To Let or For Sale</option>
            {SELECTABLE_LISTING_TYPES.map((v) => (
              <option key={v} value={v}>
                {LISTING_TYPE_LABELS[v]}
              </option>
            ))}
          </select>

          <AreaTagInput areaOptions={areas.map((a) => a.name)} initialAreas={selectedAreas} />

          <button
            type="submit"
            className="flex items-center justify-center gap-2 rounded-full bg-red-600 px-6 py-2.5 text-sm font-bold text-white hover:bg-red-700"
          >
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
              <circle cx="11" cy="11" r="8" />
              <path d="m21 21-4.3-4.3" />
            </svg>
            Search
            <span className="font-medium tabular-nums opacity-90">({properties.length} properties)</span>
          </button>
        </div>

        <div className="grid grid-cols-2 gap-2.5 sm:grid-cols-3 lg:grid-cols-5">
          <select name="type" defaultValue={type} aria-label="Property type" className={pillSelect}>
            <option value="">All Commercial</option>
            <option value="OFFICE">Office</option>
            <option value="INDUSTRIAL">Industrial</option>
            <option value="RETAIL">Retail</option>
          </select>

          <select name="minPrice" defaultValue={minPrice ? String(minPrice) : ""} aria-label="Minimum price" className={pillSelect}>
            <option value="">Min Price</option>
            {PRICE_STEPS.map((v) => (
              <option key={v} value={v}>
                R{v.toLocaleString("en-ZA")}
              </option>
            ))}
          </select>

          <select name="maxPrice" defaultValue={maxPrice ? String(maxPrice) : ""} aria-label="Maximum price" className={pillSelect}>
            <option value="">Max Price</option>
            {PRICE_STEPS.map((v) => (
              <option key={v} value={v}>
                R{v.toLocaleString("en-ZA")}
              </option>
            ))}
          </select>

          <select name="minSize" defaultValue={minSize ? String(minSize) : ""} aria-label="Minimum size" className={pillSelect}>
            <option value="">Size (m²)</option>
            {SIZE_STEPS.map((v) => (
              <option key={v} value={v}>
                {v.toLocaleString()} m²+
              </option>
            ))}
          </select>

          <details className="relative">
            <summary className={`${pillSelect} flex cursor-pointer list-none items-center justify-between`}>
              Facilities
              {checkedFacilities.size > 0 && (
                <span className="ml-1.5 rounded-full bg-red-50 px-1.5 text-xs font-semibold text-red-700">
                  {checkedFacilities.size}
                </span>
              )}
            </summary>
            <div className="absolute z-20 mt-1.5 flex w-56 flex-col gap-2 rounded border border-stone-200 bg-white p-3 shadow-lg">
              {amenities.map((a) => (
                <label key={a.id} className="flex items-center gap-2 text-sm text-stone-600">
                  <input
                    type="checkbox"
                    name="facility"
                    value={a.id}
                    defaultChecked={checkedFacilities.has(String(a.id))}
                    className="h-4 w-4 rounded border-stone-300 text-brand focus:ring-brand"
                  />
                  {a.name}
                </label>
              ))}
            </div>
          </details>
        </div>
      </form>

      <div className="mt-8 mb-4 flex flex-wrap items-center justify-between gap-3">
        <p className="text-sm text-stone-500">
          <strong className="tabular-nums text-[#231f20]">{properties.length}</strong> properties found
        </p>
        <form className="flex items-center gap-2 text-sm">
          {listingType && <input type="hidden" name="listingType" value={listingType} />}
          {type && <input type="hidden" name="type" value={type} />}
          {selectedAreas.map((a) => (
            <input key={a} type="hidden" name="area" value={a} />
          ))}
          {facilities.map((f) => (
            <input key={f} type="hidden" name="facility" value={f} />
          ))}
          {minSize > 0 && <input type="hidden" name="minSize" value={minSize} />}
          {minPrice > 0 && <input type="hidden" name="minPrice" value={minPrice} />}
          {maxPrice > 0 && <input type="hidden" name="maxPrice" value={maxPrice} />}
          <label htmlFor="sort" className="text-stone-500">
            Sort
          </label>
          <select id="sort" name="sort" defaultValue={sort} className="rounded border border-stone-300 px-2 py-1.5 text-sm">
            <option value="newest">Newest</option>
            <option value="price-asc">Price: low to high</option>
            <option value="price-desc">Price: high to low</option>
            <option value="size-desc">Size: largest first</option>
          </select>
          <button type="submit" className="rounded border border-stone-300 px-3 py-1.5 font-medium text-stone-600 hover:border-brand hover:text-brand">
            Go
          </button>
        </form>
      </div>

      {properties.length === 0 ? (
        <div className="rounded border border-dashed border-stone-300 bg-white p-12 text-center text-stone-500">
          No properties match those filters. Try broadening your search, or{" "}
          <Link href="/contact" className="font-semibold text-brand hover:text-brand-deep">
            contact a broker directly
          </Link>
          .
        </div>
      ) : (
        <div className="flex flex-col gap-6">
          {properties.map((p) => (
            <PropertyCard key={p.id} property={p} />
          ))}
        </div>
      )}
    </main>
  );
}
