import Link from "next/link";
import {
  PlusIcon,
  BellIcon,
  CalendarIcon,
  UsersIcon,
  RepeatIcon,
  PauseIcon,
  PlayIcon,
  Trash2Icon,
} from "lucide-react";
import { DateTime } from "luxon";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent } from "@/components/ui/card";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { PageShell } from "@/components/page-shell";
import { EmptyState } from "@/components/empty-state";
import { getSeededOperator } from "@/lib/operator";
import { listAccounts, listReminders } from "@/lib/queries";
import { describeRecurrence, specFromRrule } from "@/lib/recurrence";
import {
  applyReminderFilter,
  type SortKey,
  type ReminderRow,
} from "@/lib/reminder-filter";
import { ReminderFilterBar } from "@/components/reminder-filter-bar";
import { SwipeableRow } from "@/components/swipeable-row";
import {
  deleteReminderAction,
  pauseReminderAction,
  restartReminderAction,
} from "@/actions/reminders";

type FilterValue = "all" | "active" | "inactive" | "paused";

function formatWhen(date: Date | null, tz: string): string {
  if (!date) return "—";
  return new Intl.DateTimeFormat("en-MY", {
    timeZone: tz,
    month: "short",
    day: "numeric",
    hour: "numeric",
    minute: "2-digit",
  }).format(new Date(date));
}

const STATUS_STYLES: Record<string, string> = {
  active:
    "bg-emerald-500/15 text-emerald-700 dark:bg-emerald-500/20 dark:text-emerald-400 border-transparent",
  inactive:
    "bg-slate-200/60 text-slate-500 dark:bg-slate-700/40 dark:text-slate-400 border-transparent",
  paused:
    "bg-amber-500/15 text-amber-700 dark:bg-amber-500/20 dark:text-amber-400 border-transparent",
  failed:
    "bg-red-500/15 text-red-600 dark:bg-red-500/20 dark:text-red-400 border-transparent",
};

/**
 * Shared shelf-button component for swipeable reminder rows. Wraps a
 * server action in a tiny form so the row stays a server component;
 * the page revalidates after the action lands.
 */
function ReminderShelfButton({
  reminderId,
  label,
  icon,
  action,
  bg,
}: {
  reminderId: string;
  label: string;
  icon: React.ReactNode;
  action: (formData: FormData) => Promise<void>;
  bg: string;
}) {
  return (
    <form action={action} className="flex w-full">
      <input type="hidden" name="reminderId" value={reminderId} />
      <button
        type="submit"
        aria-label={label}
        className={`flex h-full w-full flex-col items-center justify-center gap-1 text-xs font-medium ${bg}`}
      >
        {icon}
        {label}
      </button>
    </form>
  );
}

function StatusPill({ status }: { status: string }) {
  const cls =
    STATUS_STYLES[status] ??
    "bg-secondary text-secondary-foreground border-transparent";
  const label = status.charAt(0).toUpperCase() + status.slice(1);
  return (
    <Badge variant="secondary" className={cls}>
      {label}
    </Badge>
  );
}

const FILTER_TABS: { value: FilterValue; label: string }[] = [
  { value: "all", label: "All" },
  { value: "active", label: "Active" },
  { value: "inactive", label: "Inactive" },
  { value: "paused", label: "Paused" },
];

const VALID_SORT_KEYS: SortKey[] = [
  "scheduled_desc",
  "scheduled_asc",
  "created_desc",
  "name_asc",
];

interface PageProps {
  searchParams: Promise<{
    filter?: string;
    q?: string;
    accountId?: string;
    sort?: string;
  }>;
}

export default async function RemindersPage({ searchParams }: PageProps) {
  const sp = await searchParams;
  const status: FilterValue =
    sp.filter === "active" || sp.filter === "inactive" || sp.filter === "paused"
      ? sp.filter
      : "all";
  // Sort is now fixed to `created_desc`. Reordering on every status flip
  // (Restart, Pause, Edit) was causing rows to jump around the list,
  // which made the swipe gesture feel like the wrong thing happened.
  // `created_at` never changes so the row stays put.
  const sort: SortKey = "created_desc";
  void VALID_SORT_KEYS; // kept for future use; no longer read from URL

  const op = await getSeededOperator();
  const tz = op.defaultTimezone ?? "UTC";

  // Run the reminder query and the filter-options query in parallel.
  // The Group filter was removed (per user request — search already
  // matches group names) so we don't need the groups list anymore.
  const [allReminders, accounts] = await Promise.all([
    listReminders(op.id),
    listAccounts(op.id),
  ]);

  const filterRows: ReminderRow[] = allReminders.map((r) => ({
    id: r.id,
    name: r.name,
    status: r.status,
    accountId: r.accountId,
    accountLabel: r.accountLabel,
    groupIds: r.groupIds,
    groupNames: r.groupNames,
    firstText: r.firstText,
    scheduledAt: r.scheduledAt,
    createdAt: r.createdAt,
  }));
  const sortedFiltered = applyReminderFilter(filterRows, {
    q: sp.q,
    accountId: sp.accountId,
    status,
    sort,
  });
  const visible = sortedFiltered
    .map((r) => allReminders.find((row) => row.id === r.id))
    .filter((r): r is (typeof allReminders)[number] => Boolean(r));

  const tabHref = (value: FilterValue): string => {
    const params = new URLSearchParams();
    if (value !== "all") params.set("filter", value);
    if (sp.q) params.set("q", sp.q);
    if (sp.accountId) params.set("accountId", sp.accountId);
    const qs = params.toString();
    return qs ? `/reminders?${qs}` : "/reminders";
  };

  const hasAnyFilter = Boolean(sp.q || sp.accountId);

  return (
    <PageShell
      title="Reminders"
      floatingAction={
        <Button
          asChild
          size="sm"
          className="rounded-full shadow-md hover:shadow-lg transition-shadow gap-1.5 sm:h-7 size-12 sm:size-auto sm:px-2.5"
        >
          {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
          <Link href={"/reminders/new" as any} aria-label="New reminder">
            <PlusIcon className="size-5 sm:size-3.5" />
            <span className="hidden sm:inline">New Reminder</span>
          </Link>
        </Button>
      }
    >
      <ReminderFilterBar
        accounts={accounts.map((a) => ({ id: a.id, label: a.label }))}
      />

      {/* Status tabs — preserve other filter params so flipping tabs doesn't lose them */}
      <Tabs value={status}>
        <TabsList className="w-full">
          {FILTER_TABS.map(({ value, label }) => (
            <TabsTrigger key={value} value={value} asChild>
              {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
              <Link href={tabHref(value) as any}>{label}</Link>
            </TabsTrigger>
          ))}
        </TabsList>
      </Tabs>

      {visible.length > 0 ? (
        <>
          <p className="text-xs text-muted-foreground sm:hidden">
            Swipe a row left to Delete, or right to{" "}
            {status === "paused" ? "Restart" : "Pause"}.
          </p>

          <div className="flex flex-col gap-3">
            {visible.map((reminder) => {
              const canPause = reminder.status === "active";
              const canRestart =
                reminder.status === "paused" || reminder.status === "inactive";
              const cardBody = (
                <Link
                  // eslint-disable-next-line @typescript-eslint/no-explicit-any
                  href={`/reminders/${reminder.id}` as any}
                  className="block rounded-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
                >
                  <Card className="transition-shadow hover:shadow-md hover:ring-foreground/20">
                    <CardContent className="flex items-center gap-3 py-3 px-4">
                      <div className="min-w-0 flex-1 space-y-1">
                        <div className="flex items-center gap-2 flex-wrap">
                          <StatusPill status={reminder.status} />
                          <span className="text-sm font-medium leading-none truncate">
                            {reminder.name}
                          </span>
                        </div>
                        <p className="text-xs text-muted-foreground truncate">
                          {reminder.accountLabel}
                          {reminder.groupNames && ` · ${reminder.groupNames}`}
                        </p>
                      </div>

                      {/* Right meta column. Capped at ~14rem so a long
                          recurrence description ("Every month on days
                          4, 6, 7, 11, 13, 14 +6 more at 11:32") can't
                          starve the reminder name on the left. min-w-0
                          + truncate on each span ellipsises overflow
                          inside the cap. Title tooltip preserves the
                          full text on hover. */}
                      <div className="min-w-0 max-w-[20%] sm:max-w-[5.5rem] text-right space-y-1">
                        <div className="flex min-w-0 items-center justify-end gap-1 text-xs text-muted-foreground">
                          <CalendarIcon className="size-3 shrink-0" />
                          <span className="truncate">
                            {formatWhen(reminder.scheduledAt, tz)}
                          </span>
                        </div>
                        {reminder.rrule && reminder.scheduledAt ? (
                          <div
                            className="flex min-w-0 items-center justify-end gap-1 text-xs text-primary/80"
                            title={describeRecurrence(
                              specFromRrule(reminder.rrule),
                              DateTime.fromJSDate(reminder.scheduledAt).setZone(reminder.timezone),
                            )}
                          >
                            <RepeatIcon className="size-3 shrink-0" />
                            <span className="truncate">
                              {describeRecurrence(
                                specFromRrule(reminder.rrule),
                                DateTime.fromJSDate(reminder.scheduledAt).setZone(reminder.timezone),
                              )}
                            </span>
                          </div>
                        ) : null}
                        {reminder.groupCount > 0 && (
                          <div className="flex min-w-0 items-center justify-end gap-1 text-xs text-muted-foreground">
                            <UsersIcon className="size-3 shrink-0" />
                            <span className="truncate">
                              {reminder.groupCount}{" "}
                              {reminder.groupCount === 1 ? "group" : "groups"}
                            </span>
                          </div>
                        )}
                      </div>
                    </CardContent>
                  </Card>
                </Link>
              );

              // Right swipe → left shelf → Pause (active) / Restart (paused or
              // ended). Left swipe → right shelf → Delete. For lifecycle
              // states with no sensible secondary action (e.g. failed) we
              // omit the left shelf so the row only swipes one direction.
              const leftShelf =
                canPause ? (
                  <ReminderShelfButton
                    reminderId={reminder.id}
                    label="Pause"
                    icon={<PauseIcon className="size-4" />}
                    action={pauseReminderAction}
                    bg="bg-amber-500/15 text-amber-700 hover:bg-amber-500/25 dark:bg-amber-500/20 dark:text-amber-400 dark:hover:bg-amber-500/30"
                  />
                ) : canRestart ? (
                  <ReminderShelfButton
                    reminderId={reminder.id}
                    label="Restart"
                    icon={<PlayIcon className="size-4" />}
                    action={restartReminderAction}
                    bg="bg-emerald-500/15 text-emerald-700 hover:bg-emerald-500/25 dark:bg-emerald-500/20 dark:text-emerald-400 dark:hover:bg-emerald-500/30"
                  />
                ) : undefined;

              return (
                <SwipeableRow
                  // Key includes both id and status so a status change
                  // (Pause / Restart / Delete result) remounts the row,
                  // which resets its swipe offset back to closed. Without
                  // this, clicking a shelf button leaves the shelf open
                  // even after the row's content updates.
                  key={`${reminder.id}-${reminder.status}`}
                  leftActions={leftShelf}
                  rightActions={
                    <ReminderShelfButton
                      reminderId={reminder.id}
                      label="Delete"
                      icon={<Trash2Icon className="size-4" />}
                      action={deleteReminderAction}
                      bg="bg-destructive/15 text-destructive hover:bg-destructive/25"
                    />
                  }
                >
                  {cardBody}
                </SwipeableRow>
              );
            })}
          </div>
        </>
      ) : (
        <EmptyState
          icon={BellIcon}
          title={
            allReminders.length === 0
              ? "No reminders yet."
              : hasAnyFilter
                ? "No reminders match your filters."
                : `No ${status} reminders yet.`
          }
          description={
            allReminders.length === 0
              ? "Create a reminder to start sending scheduled WhatsApp messages."
              : hasAnyFilter
                ? "Try clearing the filters or widening your search."
                : "Reminders in other states aren't shown by this filter."
          }
          action={
            allReminders.length === 0 ? (
              <Button asChild size="sm">
                {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
                <Link href={"/reminders/new" as any}>
                  <PlusIcon />
                  New Reminder
                </Link>
              </Button>
            ) : undefined
          }
        />
      )}
    </PageShell>
  );
}
