import { createFileRoute } from "@tanstack/react-router";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useEffect, useState } from "react";
import { Search, RefreshCw } from "lucide-react";
import { AppShell } from "@/components/AppShell";
import { EventCard, EventCardSkeleton } from "@/components/EventCard";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Switch } from "@/components/ui/switch";
import { Label } from "@/components/ui/label";
import { fetchCategories, fetchCities, fetchEvents } from "@/lib/hotspots";
import { searchExternalEvents } from "@/lib/discovery.functions";
import { toast } from "sonner";

type DiscoverSearch = {
  q?: string | undefined;
  category?: string | undefined;
  city?: string | undefined;
};

export const Route = createFileRoute("/discover")({
  validateSearch: (search: Record<string, unknown>): DiscoverSearch => ({
    q: typeof search["q"] === "string" ? (search["q"] as string) : undefined,
    category: typeof search["category"] === "string" ? (search["category"] as string) : undefined,
    city: typeof search["city"] === "string" ? (search["city"] as string) : undefined,
  }),
  head: () => ({
    meta: [
      { title: "Discover events — HOTSPOTS" },
      {
        name: "description",
        content:
          "Search events by city, category, date and price across Ghana, Nigeria, Kenya and South Africa.",
      },
      { property: "og:title", content: "Discover events — HOTSPOTS" },
      { property: "og:description", content: "Search and filter events happening around you." },
    ],
  }),
  component: DiscoverPage,
});

function DiscoverPage() {
  const search = Route.useSearch();
  const [term, setTerm] = useState(search.q ?? "");
  const [query, setQuery] = useState(search.q ?? "");
  const [citySlug, setCitySlug] = useState("");
  const [categorySlug, setCategorySlug] = useState(search.category ?? "");
  const [freeOnly, setFreeOnly] = useState(false);
  const [verifiedOnly, setVerifiedOnly] = useState(false);
  const [range, setRange] = useState<"any" | "today" | "weekend" | "month">("any");

  const { data: cities = [] } = useQuery({ queryKey: ["cities"], queryFn: fetchCities });
  const { data: categories = [] } = useQuery({ queryKey: ["categories"], queryFn: fetchCategories });

  const cityId = cities.find((c) => c.name === citySlug)?.id;
  const categoryId = categories.find((c) => c.slug === categorySlug)?.id;

  let to: string | undefined;
  const now = new Date();
  if (range === "today") {
    const d = new Date(now);
    d.setHours(23, 59, 59);
    to = d.toISOString();
  } else if (range === "weekend") {
    const d = new Date(now);
    d.setDate(d.getDate() + ((7 - d.getDay()) % 7));
    d.setHours(23, 59, 59);
    to = d.toISOString();
  } else if (range === "month") {
    const d = new Date(now);
    d.setMonth(d.getMonth() + 1);
    to = d.toISOString();
  }

  const results = useQuery({
    queryKey: ["discover", query, cityId, categoryId, freeOnly, verifiedOnly, range],
    queryFn: () =>
      fetchEvents({
        search: query || undefined,
        cityId,
        categoryId,
        freeOnly,
        verifiedOnly,
        to,
        limit: 48,
      }),
  });

  const queryClient = useQueryClient();
  const external = useQuery({
    queryKey: ["external-search", query],
    queryFn: () => searchExternalEvents({ data: { query } }),
    enabled: query.trim().length >= 2,
    staleTime: 10 * 60_000,
    retry: false,
  });

  const addedCount = external.data?.added ?? 0;
  useEffect(() => {
    if (addedCount > 0) {
      toast.success(`Found ${addedCount} new event${addedCount === 1 ? "" : "s"} from partner sources`);
      queryClient.invalidateQueries({ queryKey: ["discover"] });
    }
  }, [addedCount, queryClient]);

  const [refreshing, setRefreshing] = useState(false);
  const refresh = async () => {
    setRefreshing(true);
    try {
      // Refresh partner sources even without a search term: use a broad
      // keyword so new external events are pulled in continuously.
      const term2 = query.trim().length >= 2 ? query.trim() : "event";
      queryClient.removeQueries({ queryKey: ["external-search"] });
      const res = await searchExternalEvents({ data: { query: term2 } });
      if (res.added > 0) {
        toast.success(`Found ${res.added} new event${res.added === 1 ? "" : "s"} from partner sources`);
      } else if (res.missingKey) {
        toast.error("Partner source key is not configured");
      } else {
        toast.info("No new events from partner sources right now");
      }
      await queryClient.invalidateQueries({ queryKey: ["discover"] });
      await queryClient.invalidateQueries({ queryKey: ["events"] });
    } catch {
      toast.error("Couldn't refresh from partner sources");
    } finally {
      setRefreshing(false);
    }
  };

  return (
    <AppShell>
      <div className="space-y-6">
        <div>
          <h1 className="font-display text-2xl font-extrabold">Discover</h1>
          <p className="text-sm text-muted-foreground">
            Search HOTSPOTS for events by place, category and date.
          </p>
        </div>

        <form
          className="flex gap-2"
          onSubmit={(e) => {
            e.preventDefault();
            setQuery(term);
          }}
        >
          <div className="relative flex-1">
            <Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
            <Input
              value={term}
              onChange={(e) => setTerm(e.target.value)}
              placeholder="Search events, venues, organisers"
              className="h-11 rounded-full pl-9"
            />
          </div>
          <Button type="submit" className="h-11 rounded-full px-5">
            Search
          </Button>
          <Button
            type="button"
            variant="outline"
            onClick={refresh}
            disabled={refreshing || external.isFetching}
            className="h-11 rounded-full px-4"
            title="Fetch new events from partner sources"
          >
            <RefreshCw className={`mr-2 h-4 w-4 ${refreshing || external.isFetching ? "animate-spin" : ""}`} />
            Refresh
          </Button>
        </form>

        <div className="space-y-3 rounded-2xl border border-border bg-card p-4">
          <div className="flex flex-wrap gap-2">
            {["any", "today", "weekend", "month"].map((r) => (
              <button
                key={r}
                onClick={() => setRange(r as typeof range)}
                className={`rounded-full border px-3 py-1.5 text-xs font-medium capitalize ${
                  range === r ? "border-primary bg-primary/15 text-primary" : "border-border"
                }`}
              >
                {r === "any" ? "Any date" : r === "month" ? "Next month" : r}
              </button>
            ))}
          </div>
          <div className="flex flex-wrap gap-2">
            <button
              onClick={() => setCitySlug("")}
              className={`rounded-full border px-3 py-1.5 text-xs ${citySlug === "" ? "border-primary text-primary" : "border-border"}`}
            >
              All cities
            </button>
            {cities.map((c) => (
              <button
                key={c.id}
                onClick={() => setCitySlug(c.name)}
                className={`rounded-full border px-3 py-1.5 text-xs ${citySlug === c.name ? "border-primary text-primary" : "border-border"}`}
              >
                {c.name}
              </button>
            ))}
          </div>
          <div className="flex flex-wrap gap-2">
            <button
              onClick={() => setCategorySlug("")}
              className={`rounded-full border px-3 py-1.5 text-xs ${categorySlug === "" ? "border-primary text-primary" : "border-border"}`}
            >
              All categories
            </button>
            {categories.map((c) => (
              <button
                key={c.id}
                onClick={() => setCategorySlug(c.slug)}
                className={`rounded-full border px-3 py-1.5 text-xs ${categorySlug === c.slug ? "border-primary text-primary" : "border-border"}`}
              >
                {c.emoji} {c.name}
              </button>
            ))}
          </div>
          <div className="flex flex-wrap items-center gap-6 pt-1">
            <div className="flex items-center gap-2">
              <Switch id="free" checked={freeOnly} onCheckedChange={setFreeOnly} />
              <Label htmlFor="free" className="text-xs">
                Free only
              </Label>
            </div>
            <div className="flex items-center gap-2">
              <Switch id="verified" checked={verifiedOnly} onCheckedChange={setVerifiedOnly} />
              <Label htmlFor="verified" className="text-xs">
                Verified only
              </Label>
            </div>
          </div>
        </div>

        {results.isLoading ? (
          <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
            {Array.from({ length: 6 }).map((_, i) => (
              <EventCardSkeleton key={i} />
            ))}
          </div>
        ) : (results.data ?? []).length === 0 ? (
          <div className="rounded-2xl border border-border bg-card p-10 text-center">
            <p className="font-display text-lg font-bold">No events match that yet</p>
            <p className="mt-1 text-sm text-muted-foreground">
              Try a different city, category or date range.
            </p>
          </div>
        ) : (
          <>
            <div className="flex items-center gap-2 text-xs text-muted-foreground">
              <p>{results.data?.length} events found</p>
              {external.isFetching && <p>· Searching partner event sources for more…</p>}
            </div>
            <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
              {results.data?.map((event) => <EventCard key={event.id} event={event} />)}
            </div>
          </>
        )}
      </div>
    </AppShell>
  );
}
