import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useQueryClient } from "@tanstack/react-query";
import {
  useUpdateLanguage,
  getGetMeQueryKey,
} from "@workspace/api-client-react";
import {
  Settings as SettingsIcon,
  Volume2,
  VolumeX,
  LayoutGrid,
} from "lucide-react";
import {
  Sheet,
  SheetContent,
  SheetHeader,
  SheetTitle,
} from "@/components/ui/sheet";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import {
  Accordion,
  AccordionItem,
  AccordionTrigger,
  AccordionContent,
} from "@/components/ui/accordion";
import { useAuth } from "@/contexts/AuthContext";
import {
  NotificationSettingsContent,
  useUpdatePrefs,
} from "@/components/notification-settings";
import { ClockStyleContent } from "@/components/clock-style-picker";
import { useMediaQuery } from "@/hooks/use-media-query";
import { useDockVisible } from "@/hooks/use-dock-visible";
import i18n from "@/i18n";

function ToggleRow({
  active,
  onClick,
  label,
  ariaLabel,
  leftIcon,
}: {
  active: boolean;
  onClick: () => void;
  label: string;
  ariaLabel?: string;
  leftIcon?: React.ReactNode;
}) {
  return (
    <button
      type="button"
      role="switch"
      aria-checked={active}
      aria-label={ariaLabel ?? label}
      onClick={onClick}
      className="w-full flex items-center justify-between gap-3 px-3 py-2.5 rounded-lg text-start hover:bg-foreground/5 transition-colors"
    >
      <div className="flex items-center gap-2 min-w-0">
        {leftIcon}
        <span className="text-sm text-foreground font-medium truncate">{label}</span>
      </div>
      <span
        className={`relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-colors ${
          active ? "bg-primary" : "bg-foreground/15"
        }`}
        aria-hidden="true"
      >
        <span
          className={`inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${
            active
              ? "translate-x-[18px] rtl:-translate-x-[18px]"
              : "translate-x-0.5 rtl:-translate-x-0.5"
          }`}
        />
      </span>
    </button>
  );
}

function LanguageBody() {
  const { t, i18n: i18nInstance } = useTranslation();
  const queryClient = useQueryClient();
  const updateLanguage = useUpdateLanguage();
  const current = i18nInstance.language === "ar" ? "ar" : "en";

  const choose = (next: "ar" | "en") => {
    if (next === current) return;
    i18n.changeLanguage(next);
    updateLanguage.mutate(
      { data: { language: next } },
      {
        onSuccess: () => {
          queryClient.invalidateQueries({ queryKey: getGetMeQueryKey() });
        },
      },
    );
  };

  const options: Array<{ value: "ar" | "en"; label: string }> = [
    { value: "ar", label: t("settingsPanel.lang.ar") },
    { value: "en", label: t("settingsPanel.lang.en") },
  ];

  return (
    <div
      className="grid grid-cols-2 gap-1 p-1 rounded-lg bg-foreground/5"
      role="radiogroup"
      aria-label={t("settingsPanel.section.language")}
    >
      {options.map((opt) => {
        const isActive = opt.value === current;
        return (
          <button
            key={opt.value}
            type="button"
            role="radio"
            aria-checked={isActive}
            onClick={() => choose(opt.value)}
            data-testid={`settings-lang-${opt.value}`}
            className={`text-sm font-medium px-2 py-1.5 rounded-md transition-colors ${
              isActive
                ? "bg-background text-foreground shadow-sm"
                : "text-muted-foreground hover:text-foreground"
            }`}
          >
            {opt.label}
          </button>
        );
      })}
    </div>
  );
}

/**
 * Single toggle to hide/show the bottom AppDock bar.
 * Preference is per-device (localStorage) and the AppDock listens to
 * the same hook so the change is instant without a reload.
 */
function DockBody() {
  const { t } = useTranslation();
  const [visible, setVisible] = useDockVisible();
  return (
    <ToggleRow
      active={visible}
      onClick={() => setVisible(!visible)}
      label={t("settingsPanel.dock.show")}
      leftIcon={
        <LayoutGrid
          size={16}
          className={visible ? "text-primary shrink-0" : "text-muted-foreground shrink-0"}
        />
      }
    />
  );
}

function SoundBody() {
  const { t } = useTranslation();
  const { user } = useAuth();
  const apply = useUpdatePrefs();
  if (!user) return null;
  const muted = user.notificationsMuted;
  return (
    <ToggleRow
      active={!muted}
      onClick={() => apply({ notificationsMuted: !muted })}
      label={t("settingsPanel.sound.master")}
      leftIcon={
        muted ? (
          <VolumeX size={16} className="text-muted-foreground shrink-0" />
        ) : (
          <Volume2 size={16} className="text-primary shrink-0" />
        )
      }
    />
  );
}

type GroupId = "dock" | "language" | "notifications" | "sound" | "clock";

/**
 * Section wrapper that styles each accordion item like the existing
 * GroupCard so the panel keeps its rounded-card visual rhythm even
 * when collapsed. The chevron is rendered by AccordionTrigger and
 * rotates on open via the `[&[data-state=open]>svg]:rotate-180`
 * utility already baked into the shadcn primitive.
 */
function GroupItem({
  id,
  title,
  children,
}: {
  id: GroupId;
  title: string;
  children: React.ReactNode;
}) {
  return (
    <AccordionItem
      value={id}
      className="rounded-xl border border-foreground/10 bg-background/40 overflow-hidden border-b"
    >
      <AccordionTrigger
        data-testid={`settings-group-${id}`}
        className="px-3 py-2.5 text-sm font-semibold text-foreground text-start hover:no-underline hover:bg-foreground/5"
      >
        {title}
      </AccordionTrigger>
      <AccordionContent className="px-2 pb-2 pt-0">
        {children}
      </AccordionContent>
    </AccordionItem>
  );
}

/**
 * Body of the unified per-user Settings panel. Composes the existing
 * form components from `notification-settings.tsx` and
 * `clock-style-picker.tsx` rather than re-implementing them, so all
 * persistence + behaviour stays identical to the topbar buttons that
 * used to expose them.
 *
 * groups are collapsible. Open/closed state is lifted up
 * to the SettingsPanel so it persists while the panel is closed and
 * re-opened in the same session. Default = all collapsed (compact
 * panel on first open).
 */
function SettingsPanelBody({
  openGroups,
  onOpenChange,
}: {
  openGroups: GroupId[];
  onOpenChange: (next: GroupId[]) => void;
}) {
  const { t } = useTranslation();
  const { user } = useAuth();
  if (!user) return null;
  return (
    <Accordion
      type="multiple"
      value={openGroups}
      onValueChange={(v) => onOpenChange(v as GroupId[])}
      className="space-y-2"
    >
      <GroupItem id="dock" title={t("settingsPanel.section.dock")}>
        <DockBody />
      </GroupItem>
      <GroupItem id="language" title={t("settingsPanel.section.language")}>
        <LanguageBody />
      </GroupItem>
      <GroupItem id="notifications" title={t("settingsPanel.section.notifications")}>
        <NotificationSettingsContent />
      </GroupItem>
      <GroupItem id="sound" title={t("settingsPanel.section.sound")}>
        <SoundBody />
      </GroupItem>
      <GroupItem id="clock" title={t("settingsPanel.section.clock")}>
        <ClockStyleContent
          currentStyle={user.clockStyle ?? null}
          currentHour12={user.clockHour12 ?? null}
        />
      </GroupItem>
    </Accordion>
  );
}

/**
 * Unified per-user Settings panel.
 *
 * - Trigger: a single gear icon in the topbar that replaces the
 *   per-user preference buttons (language globe, quick-mute volume,
 *   notification-settings bell, clock-style picker).
 * - Surface: an anchored Popover on `md:` (>=768px) viewports;
 *   a bottom Sheet on smaller screens. Both render the same body so
 *   behaviour and accessibility stay consistent.
 * - Body composes the existing form components rather than
 *   re-implementing them, preserving DB + localStorage persistence.
 * -: groups are collapsible (accordion); logout stays
 *   in the topbar so the gear panel only hosts preferences.
 */
export function SettingsPanel() {
  const { t } = useTranslation();
  const [open, setOpen] = useState(false);
  // Default = all collapsed so the panel opens compact.
  // State is lifted here so toggles persist while the panel is
  // dismissed and re-opened in the same session.
  const [openGroups, setOpenGroups] = useState<GroupId[]>([]);
  const { user } = useAuth();
  const isDesktop = useMediaQuery("(min-width: 768px)");
  if (!user) return null;

  const trigger = (
    <button
      type="button"
      aria-label={t("settingsPanel.title")}
      aria-haspopup="dialog"
      data-testid="topbar-settings-button"
      className="text-muted-foreground hover:text-foreground transition-colors p-1.5 md:p-2.5 rounded-lg md:rounded-xl hover:bg-foreground/5"
    >
      <SettingsIcon className="w-[18px] h-[18px] md:w-6 md:h-6" />
    </button>
  );

  if (isDesktop) {
    return (
      <Popover open={open} onOpenChange={setOpen}>
        <PopoverTrigger asChild>{trigger}</PopoverTrigger>
        <PopoverContent
          align="end"
          className="w-96 p-3 max-h-[80vh] overflow-y-auto"
          data-testid="settings-panel"
        >
          <div className="px-1 pb-2 flex items-center gap-2 text-sm font-semibold text-foreground">
            <SettingsIcon size={16} />
            {t("settingsPanel.title")}
          </div>
          <SettingsPanelBody
            openGroups={openGroups}
            onOpenChange={setOpenGroups}
          />
        </PopoverContent>
      </Popover>
    );
  }

  return (
    <Sheet open={open} onOpenChange={setOpen}>
      <button
        type="button"
        onClick={() => setOpen(true)}
        aria-label={t("settingsPanel.title")}
        aria-haspopup="dialog"
        data-testid="topbar-settings-button"
        className="text-muted-foreground hover:text-foreground transition-colors p-1.5 rounded-lg hover:bg-foreground/5"
      >
        <SettingsIcon className="w-[18px] h-[18px]" />
      </button>
      <SheetContent
        side="bottom"
        className="h-[85vh] p-0 flex flex-col rounded-t-2xl"
        data-testid="settings-panel"
      >
        <SheetHeader className="px-4 pt-4 pb-2 shrink-0 border-b border-foreground/10">
          <SheetTitle className="flex items-center gap-2 text-base">
            <SettingsIcon size={18} />
            {t("settingsPanel.title")}
          </SheetTitle>
        </SheetHeader>
        <div className="flex-1 overflow-y-auto p-3">
          <SettingsPanelBody
            openGroups={openGroups}
            onOpenChange={setOpenGroups}
          />
        </div>
      </SheetContent>
    </Sheet>
  );
}
