"use client";

import { useEffect, useRef, useState } from "react";
import { Bookmark, MoreHorizontal, Star, Trash2 } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { FieldGroup } from "@/components/ui/field";
import { Spinner } from "@/components/ui/spinner";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { FormErrorAlert, SwitchField, TextField } from "@/components/app/form-fields";
import { cn } from "@/lib/utils";
import { canonicalFilters, useSaveViewForm, useSavedViews } from "@/app/lib/useSavedViews";

/**
 * Saved views for any list screen: chips that re-apply saved filters, a "Save view" button, and
 * (optionally) the user's default view applied when the list opens without filters.
 *
 *   <SavedViewsBar module="shipments" noun="shipments" filters={filters} sort={sort}
 *     onApply={(view) => replaceUrl({ ...view.filters, ...view.sort })} applyDefault />
 *
 * `filters` / `sort` are the list's current URL state (plain objects); `module` must be in SaveSavedView::MODULES.
 */
export function SavedViewsBar({ module, noun = "records", filters = {}, sort = null, onApply, applyDefault = false, className }) {
  const savedViews = useSavedViews(module, { noun });
  const [saveOpen, setSaveOpen] = useState(false);
  const defaultApplied = useRef(false);
  const current = canonicalFilters(filters);
  const activeView = savedViews.views.find((view) => canonicalFilters(view.filters) === current);
  const isEmpty = current === "[]";

  // Open the default view once, only when the user arrived without filters in the URL.
  useEffect(() => {
    if (!applyDefault || defaultApplied.current || !savedViews.hasLoaded) return;
    defaultApplied.current = true;
    const fallback = savedViews.views.find((view) => view.is_default);
    if (fallback && isEmpty) onApply?.(fallback);
  }, [applyDefault, isEmpty, onApply, savedViews.hasLoaded, savedViews.views]);

  return <div className={cn("flex flex-wrap items-center gap-2", className)}>
    {savedViews.views.length > 0 && <span className="text-sm text-muted-foreground">Saved views</span>}
    {savedViews.views.map((view) => <div key={view.id} className={cn("flex items-center rounded-md border bg-background shadow-xs", activeView?.id === view.id && "border-primary/40 bg-primary/5")}>
      <Button variant="ghost" size="sm" className="h-8 rounded-r-none" aria-pressed={activeView?.id === view.id} onClick={() => onApply?.(view)}>
        {view.is_default && <Star className="fill-current text-warning" aria-label="Default view" />}{view.name}
      </Button>
      <DropdownMenu>
        <DropdownMenuTrigger asChild><Button variant="ghost" size="icon" className="size-8 rounded-l-none" aria-label={`Options for ${view.name}`}><MoreHorizontal /></Button></DropdownMenuTrigger>
        <DropdownMenuContent align="end">
          {!view.is_default && <DropdownMenuItem onSelect={() => savedViews.makeDefault(view)}><Star /> Make default</DropdownMenuItem>}
          <DropdownMenuItem variant="destructive" onSelect={() => savedViews.remove(view)}><Trash2 /> Delete view</DropdownMenuItem>
        </DropdownMenuContent>
      </DropdownMenu>
    </div>)}
    {activeView
      ? <Tooltip>
        <TooltipTrigger asChild><span tabIndex={0}><Button variant="outline" size="sm" disabled><Bookmark /> Save view</Button></span></TooltipTrigger>
        <TooltipContent>These filters are already saved as “{activeView.name}”. Change a filter to save a new view.</TooltipContent>
      </Tooltip>
      : <Button variant="outline" size="sm" onClick={() => setSaveOpen(true)}><Bookmark /> Save view</Button>}
    <SaveViewDialog open={saveOpen} onOpenChange={setSaveOpen} savedViews={savedViews} filters={filters} sort={sort} noun={noun} />
  </div>;
}

function SaveViewDialog({ open, onOpenChange, savedViews, filters, sort, noun }) {
  const { form, submit } = useSaveViewForm(savedViews, { filters, sort, onDone: () => onOpenChange(false) });
  const filterCount = JSON.parse(canonicalFilters(filters)).length;

  return <Dialog open={open} onOpenChange={(next) => { if (!next) form.reset(); onOpenChange(next); }}>
    <DialogContent className="sm:max-w-md">
      <form onSubmit={submit} className="grid gap-5">
        <DialogHeader>
          <DialogTitle>Save current view</DialogTitle>
          <DialogDescription>{filterCount ? `${filterCount} ${filterCount === 1 ? "filter" : "filters"}` : "No filters"}{sort ? " and the current sort" : ""} will be saved. Only you can see your saved views.</DialogDescription>
        </DialogHeader>
        <FormErrorAlert form={form} />
        <FieldGroup>
          <TextField control={form.control} name="name" label="View name" placeholder="e.g. My open items" inputProps={{ autoFocus: true }} />
          <SwitchField control={form.control} name="isDefault" label="Open by default" description={`Show this view when I open ${noun}.`} />
        </FieldGroup>
        <DialogFooter>
          <Button type="button" variant="outline" onClick={() => onOpenChange(false)}>Cancel</Button>
          <Button type="submit" disabled={form.formState.isSubmitting}>{form.formState.isSubmitting && <Spinner />} Save view</Button>
        </DialogFooter>
      </form>
    </DialogContent>
  </Dialog>;
}
