"use client";

import { Suspense, useState } from "react";
import Link from "next/link";
import { format as formatDay } from "date-fns";
import { CalendarRange, History, RefreshCw, SlidersHorizontal } from "lucide-react";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { Card } from "@/components/ui/card";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Sheet, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle } from "@/components/ui/sheet";
import { Skeleton } from "@/components/ui/skeleton";
import { Spinner } from "@/components/ui/spinner";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { ActiveFilters, FilterCombobox, SearchInput } from "@/components/app/filters";
import { ListPageSkeleton, PageContent, PageHeader } from "@/components/app/page";
import { cn } from "@/lib/utils";
import { useAuth } from "../auth/auth-context";
import ProtectedRoute from "../auth/protected-route";
import AppShell from "../components/app-shell";
import { EmptyState, ErrorState, UnauthorizedState } from "../components/ui/page-states";
import { TeachingEmptyState } from "../onboarding/teaching-empty-state";
import { formatDate, humanize } from "../lib/format";
import { useDebouncedSearch } from "../lib/useDebouncedSearch";
import { useTeamMemberOptions } from "../lib/useTeamMemberOptions";
import { useUrlFilters } from "../lib/useUrlFilters";
import { BurstRow, EntryRow } from "./activity-entry";
import { AREA_OPTIONS, dhakaDay, RANGE_OPTIONS, RECORD_TYPE_OPTIONS, rangeDates, useActivityFeed } from "./useActivityFeed";

const FILTER_KEYS = ["q", "user", "area", "range", "from", "to", "type"];

export function ActivityPage() {
  return <ProtectedRoute><AppShell title="Activity" subtitle="Organization log">
    <Suspense fallback={<ListPageSkeleton filters={3} rows={8} />}><ActivityFeed /></Suspense>
  </AppShell></ProtectedRoute>;
}

function initials(name) {
  return (name || "?").split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0].toUpperCase()).join("");
}

function dayLabel(key) {
  if (key === dhakaDay(new Date())) return "Today";
  if (key === dhakaDay(new Date(Date.now() - 86_400_000))) return "Yesterday";
  return formatDate(key, "Date not recorded");
}

const shortDate = (value) => (value ? formatDate(value).replace(/, \d{4}$/, "") : "…");

function rangeLabel(range, from, to) {
  if (range === "custom" || (!range && (from || to))) return from || to ? `${shortDate(from)} – ${shortDate(to)}` : "Custom";
  return RANGE_OPTIONS.find((option) => option.value === (range || "all"))?.label || "All";
}

function ActivityFeed() {
  const { can } = useAuth();
  const canView = can("activity.view_record") || can("activity.view_security");
  const { state, update, clear } = useUrlFilters(FILTER_KEYS);
  const [search, setSearch] = useDebouncedSearch(state.q, (q) => update({ q }));
  const [filtersOpen, setFiltersOpen] = useState(false);
  const team = useTeamMemberOptions(canView);
  const dates = rangeDates(state.range, state.from, state.to);
  const feed = useActivityFeed({ q: state.q, actorId: state.user, area: state.area, targetType: state.type, ...dates }, canView);

  if (!canView) {
    return <PageContent><Card className="py-0"><UnauthorizedState title="You don't have access to the activity log" permission="activity.view_record" backHref="/" backLabel="Back to dashboard" /></Card></PageContent>;
  }

  const range = state.range || (state.from || state.to ? "custom" : "all");
  const hasFilters = Boolean(state.q || state.user || state.area || state.type || range !== "all");
  const panelFilterCount = [range !== "all", state.user, state.area, state.type].filter(Boolean).length;
  const memberName = (id) => team.options.find((option) => option.value === id)?.label || "Selected member";
  const chips = [
    state.q && { key: "q", label: "Search", value: state.q },
    range !== "all" && { key: "range", label: "Dates", value: rangeLabel(state.range, state.from, state.to) },
    state.user && { key: "user", label: "Person", value: memberName(state.user) },
    state.area && { key: "area", label: "Area", value: AREA_OPTIONS.find((option) => option.value === state.area)?.label || humanize(state.area) },
    state.type && { key: "type", label: "Record", value: RECORD_TYPE_OPTIONS.find((option) => option.value === state.type)?.label || humanize(state.type) },
  ].filter(Boolean);
  const removeChip = (key) => update(key === "range" ? { range: "", from: "", to: "" } : { [key]: "" });
  const firstLoad = feed.isLoading && !feed.hasLoaded;
  const setRange = (next) => update({ range: next === "all" ? "" : next, from: "", to: "" });
  const setCustom = ({ from, to }) => update({ range: "custom", from, to });


  return <PageContent className="max-w-6xl">
    <PageHeader
      title="Activity"
      description="Who did what across the organization, newest first. Times are Asia/Dhaka; open a record for its full history."
    />

    <div className="flex flex-col gap-3">
      <div className="flex flex-wrap items-center gap-2">
        <SearchInput value={search} onChange={setSearch} placeholder="Search codes or text…" className="min-w-0 flex-1 sm:w-72 sm:flex-none" />
        <div className="hidden flex-wrap items-center gap-2 md:flex">
          <RangeControl value={range} from={state.from} to={state.to} onPreset={setRange} onCustom={setCustom} />
          <FilterCombobox label="Person" value={state.user} onChange={(user) => update({ user })} options={team.options} allLabel="Everyone" searchPlaceholder="Search people…" />
        </div>
        <Button variant="outline" size="sm" className="h-9 md:hidden" onClick={() => setFiltersOpen(true)} aria-label={`Filters${panelFilterCount ? `, ${panelFilterCount} active` : ""}`}>
          <SlidersHorizontal /> Filters{panelFilterCount > 0 && <Badge variant="secondary" className="ml-0.5 h-5 min-w-5 px-1 tabular-nums">{panelFilterCount}</Badge>}
        </Button>
        <Tooltip>
          <TooltipTrigger asChild><Button variant="outline" size="icon" className="md:ml-auto" aria-label="Refresh activity" onClick={feed.refresh} disabled={feed.isLoading}><RefreshCw className={cn(feed.isLoading && feed.hasLoaded && "animate-spin")} /></Button></TooltipTrigger>
          <TooltipContent>Refresh</TooltipContent>
        </Tooltip>
      </div>
      <div className="hidden md:block"><AreaChips value={state.area} counts={feed.meta?.areaCounts} onChange={(area) => update({ area })} /></div>
      {chips.length > 0 && <ActiveFilters chips={chips} onRemove={removeChip} onClear={clear} />}
    </div>

    <Sheet open={filtersOpen} onOpenChange={setFiltersOpen}>
      <SheetContent side="bottom" className="max-h-[85svh] gap-0 overflow-y-auto rounded-t-xl">
        <SheetHeader><SheetTitle>Filter activity</SheetTitle><SheetDescription>Narrow the log by date, person, and area.</SheetDescription></SheetHeader>
        <div className="grid gap-5 px-4 pb-2">
          <FilterSection label="Dates"><RangeControl value={range} from={state.from} to={state.to} onPreset={setRange} onCustom={setCustom} stacked /></FilterSection>
          <FilterSection label="Person"><FilterCombobox label="Person" value={state.user} onChange={(user) => update({ user })} options={team.options} allLabel="Everyone" searchPlaceholder="Search people…" className="w-full" /></FilterSection>
          <FilterSection label="Area"><AreaChips value={state.area} counts={feed.meta?.areaCounts} onChange={(area) => update({ area })} /></FilterSection>
        </div>
        <SheetFooter className="flex-row justify-end">
          {panelFilterCount > 0 && <Button variant="outline" onClick={() => update({ range: "", from: "", to: "", user: "", area: "", type: "" })}>Reset filters</Button>}
          <Button onClick={() => setFiltersOpen(false)}>Show {feed.total.toLocaleString("en-US")} actions</Button>
        </SheetFooter>
      </SheetContent>
    </Sheet>

    {!feed.error && feed.meta?.summary && feed.total > 0 && <SummaryStrip summary={feed.meta.summary} range={rangeLabel(state.range, state.from, state.to)} isAll={range === "all"} />}

    <div className={cn("grid gap-4 transition-opacity", feed.isLoading && feed.hasLoaded && "opacity-60")} aria-busy={feed.isLoading}>
      {firstLoad && <FeedSkeleton />}
      {!firstLoad && feed.error && <Card className="py-0"><ErrorState compact error={feed.error} title="Activity could not be loaded" onRetry={feed.refresh} /></Card>}
      {!firstLoad && !feed.error && !feed.count && (hasFilters
        ? <EmptyState compact icon={History} filtered onClearFilters={clear} title="No activity matches these filters" detail="Try a wider date range, another area, or clear the filters." />
        : <TeachingEmptyState k="activity" compact icon={History} showSample={false} />)}
      {!feed.error && feed.days.map((day) => <section key={day.key} aria-labelledby={`day-${day.key}`}>
        <h2 id={`day-${day.key}`} className="sticky top-14 z-10 flex items-baseline justify-between gap-2 bg-background py-2 text-sm font-medium">
          <span>{dayLabel(day.key)}</span>
          <span className="text-xs font-normal text-muted-foreground tabular-nums">{day.entries.length} {day.entries.length === 1 ? "action" : "actions"}{feed.hasMore && day === feed.days[feed.days.length - 1] ? " so far" : ""}</span>
        </h2>
        <Card className="gap-0 py-0">
          <ol className="divide-y">
            {day.groups.map((group) => (group.entries.length > 1
              ? <BurstRow key={group.key} group={group} showArea={!state.area} />
              : <EntryRow key={group.key} entry={group.entries[0]} showArea={!state.area} />))}
          </ol>
        </Card>
      </section>)}
      {!feed.error && feed.count > 0 && <div className="flex flex-col items-center gap-2 py-2 text-sm text-muted-foreground">
        {feed.moreError && <p role="alert" className="text-destructive">More activity could not be loaded.</p>}
        {feed.hasMore
          ? <Button variant="outline" size="sm" onClick={feed.loadMore} disabled={feed.isLoadingMore}>{feed.isLoadingMore && <Spinner />}{feed.moreError ? "Try again" : "Load more"}</Button>
          : <p>That&apos;s everything for these filters.</p>}
        <p className="text-xs tabular-nums">Showing {feed.count.toLocaleString("en-US")} of {feed.total.toLocaleString("en-US")} actions</p>
      </div>}
    </div>
  </PageContent>;
}

function FilterSection({ label, children }) {
  return <div className="grid gap-2"><p className="text-sm font-medium">{label}</p>{children}</div>;
}

/** Segmented date presets; "Custom" opens a range calendar. Dates are Asia/Dhaka days. */
function RangeControl({ value, from, to, onPreset, onCustom, stacked = false }) {
  const [open, setOpen] = useState(false);
  const [draft, setDraft] = useState(undefined);
  const toDate = (text) => (text ? new Date(`${text}T00:00:00`) : undefined);
  const openCustom = (next) => {
    if (next) setDraft(from || to ? { from: toDate(from), to: toDate(to) } : undefined);
    setOpen(next);
  };
  const apply = () => {
    if (!draft?.from) return;
    onCustom({ from: formatDay(draft.from, "yyyy-MM-dd"), to: formatDay(draft.to || draft.from, "yyyy-MM-dd") });
    setOpen(false);
  };

  return <ToggleGroup
    type="single"
    value={value}
    onValueChange={(next) => { if (next && next !== "custom") onPreset(next); }}
    aria-label="Date range"
    className={cn("rounded-lg bg-muted p-0.5", stacked && "grid w-full grid-cols-5")}
  >
    {RANGE_OPTIONS.filter((option) => option.value !== "custom").map((option) => <ToggleGroupItem key={option.value} value={option.value} size="sm" className={cn("h-8 rounded-md px-2.5 text-muted-foreground data-[state=on]:bg-background data-[state=on]:text-foreground data-[state=on]:shadow-sm", stacked && "px-1")}>{option.label}</ToggleGroupItem>)}
    <Popover open={open} onOpenChange={openCustom}>
      <PopoverTrigger asChild>
        <ToggleGroupItem value="custom" size="sm" className={cn("h-8 rounded-md px-2.5 text-muted-foreground data-[state=on]:bg-background data-[state=on]:text-foreground data-[state=on]:shadow-sm", stacked && "px-1")}>
          {!stacked && <CalendarRange />} {value === "custom" && !stacked ? rangeLabel("custom", from, to) : "Custom"}
        </ToggleGroupItem>
      </PopoverTrigger>
      <PopoverContent className="w-auto p-0" align="start">
        <Calendar mode="range" numberOfMonths={stacked ? 1 : 2} selected={draft} onSelect={setDraft} defaultMonth={draft?.from || new Date(Date.now() - 30 * 86_400_000)} disabled={{ after: new Date() }} />
        <div className="flex items-center justify-between gap-2 border-t p-3">
          <p className="text-xs text-muted-foreground">{draft?.from ? `${formatDate(formatDay(draft.from, "yyyy-MM-dd"))} – ${draft.to ? formatDate(formatDay(draft.to, "yyyy-MM-dd")) : "pick an end day"}` : "Pick the first day."}</p>
          <Button size="sm" onClick={apply} disabled={!draft?.from}>Apply</Button>
        </div>
      </PopoverContent>
    </Popover>
  </ToggleGroup>;
}

/** Area filter chips with the number of actions in each area for the other filters. */
function AreaChips({ value, counts, onChange }) {
  const total = counts ? Object.values(counts).reduce((sum, count) => sum + count, 0) : null;
  const options = [{ value: "all", label: "All", count: total }, ...AREA_OPTIONS.map((option) => ({ ...option, count: counts?.[option.value] ?? null }))];
  return <ToggleGroup type="single" value={value || "all"} onValueChange={(next) => next && onChange(next === "all" ? "" : next)} spacing={1.5} aria-label="Area" className="w-full flex-wrap">
    {options.map((option) => <ToggleGroupItem
      key={option.value}
      value={option.value}
      variant="outline"
      size="sm"
      disabled={option.count === 0 && option.value !== "all" && (value || "all") !== option.value}
      className="h-8 rounded-full px-2.5 data-[state=on]:border-primary data-[state=on]:bg-primary data-[state=on]:text-primary-foreground"
    >
      {option.label}
      {option.count !== null && <span className="text-xs tabular-nums opacity-70">{option.count.toLocaleString("en-US")}</span>}
    </ToggleGroupItem>)}
  </ToggleGroup>;
}

/** Small facts for the current filters: action count, people active, most active records. */
function SummaryStrip({ summary, range, isAll }) {
  const shown = summary.actors.slice(0, 5);
  return <div className="flex flex-wrap items-center gap-x-6 gap-y-3 rounded-xl border bg-card px-4 py-3 text-sm shadow-xs">
    <p><span className="font-semibold tabular-nums">{summary.total.toLocaleString("en-US")}</span> <span className="text-muted-foreground">{summary.total === 1 ? "action" : "actions"} {isAll ? "in total" : range === "Today" ? "today" : `· ${range}`}</span></p>
    {shown.length > 0 && <div className="flex items-center gap-2">
      <div className="flex -space-x-1.5">
        {shown.map((actor) => <Tooltip key={actor.id}>
          <TooltipTrigger asChild>
            <button type="button" className="rounded-full focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none" aria-label={`${actor.name}, ${actor.count} actions`}>
              <Avatar className="size-8 ring-2 ring-card"><AvatarFallback className="bg-muted text-xs font-semibold">{initials(actor.name)}</AvatarFallback></Avatar>
            </button>
          </TooltipTrigger>
          <TooltipContent>{actor.name} · {actor.count} {actor.count === 1 ? "action" : "actions"}</TooltipContent>
        </Tooltip>)}
      </div>
      <span className="text-muted-foreground">{summary.actorCount} {summary.actorCount === 1 ? "person" : "people"} active</span>
    </div>}
    {summary.topRecords.length > 0 && <div className="flex min-w-0 flex-wrap items-center gap-2">
      <span className="text-muted-foreground">Most active</span>
      {summary.topRecords.map((record) => <Badge key={record.code} variant="outline" asChild className="h-7 gap-1.5 rounded-md font-medium">
        <Link href={record.route || "#"} aria-label={`${record.label} ${record.code}, ${record.count} actions`}>{record.code}<span className="text-muted-foreground tabular-nums">{record.count}</span></Link>
      </Badge>)}
    </div>}
  </div>;
}

function FeedSkeleton() {
  return <div role="status" aria-label="Loading activity" className="grid gap-4">
    <Skeleton className="h-12 rounded-xl" />
    <div className="grid gap-2">
      <Skeleton className="h-4 w-20" />
      <Card className="gap-0 py-0">
        {Array.from({ length: 7 }).map((_, index) => <div key={index} className="flex items-start gap-3 border-b px-4 py-3 last:border-0">
          <Skeleton className="size-8 rounded-full" />
          <div className="grid flex-1 gap-1.5"><Skeleton className="h-4 w-3/4" /><Skeleton className="h-3 w-32" /></div>
          <Skeleton className="hidden h-3 w-14 sm:block" />
        </div>)}
      </Card>
    </div>
  </div>;
}
