import type { ComponentType, ReactNode } from 'react';
import { useState } from 'react';
import { NavLink, Navigate, useParams } from 'react-router';
import type { LucideIcon } from 'lucide-react';
import { Input } from '@/components/ui/input';

export type SettingsSection = {
  key: string;
  icon: LucideIcon;
  title: string;
  description: string;
  content: ReactNode;
};

export type SettingsSectionGroup = {
  label: string;
  icon: LucideIcon;
  sections: SettingsSection[];
};

type SettingsSidebarProps = {
  basePath: string;
  icon: LucideIcon;
  label: string;
  sections: SettingsSection[];
  groups?: SettingsSectionGroup[];
  hideHeader?: boolean;
};

/**
 * A real link, not a button with an onClick. The section is in the URL, so cmd-click opens it in a tab,
 * the browser knows it has been visited, and `isActive` comes from the router instead of from a global
 * that the content pane had to be told about separately.
 */
const SectionLink = ({ section, to }: { section: SettingsSection; to: string }) => (
  <NavLink
    to={to}
    className={({ isActive }) =>
      `flex items-start gap-2.5 py-2 px-3 rounded-lg text-left cursor-pointer transition-colors ${
        isActive
          ? 'bg-duck-teal/10 text-duck-dark dark:text-foreground'
          : 'text-duck-dark/70 dark:text-foreground/70 hover:bg-duck-dark/5 dark:hover:bg-foreground/5 hover:text-duck-dark dark:hover:text-foreground'
      }`
    }
  >
    {({ isActive }) => (
      <>
        <section.icon
          className={`h-3.5 w-3.5 shrink-0 mt-0.5 ${isActive ? 'text-duck-teal' : 'text-duck-dark/40 dark:text-foreground/40'}`}
        />
        <div className="min-w-0 flex-1">
          <div className="text-sm font-medium truncate">{section.title}</div>
          <div className="text-xs text-duck-dark/40 dark:text-foreground/40 truncate">{section.description}</div>
        </div>
      </>
    )}
  </NavLink>
);

export const SettingsSidebar = ({
  basePath,
  icon: Icon,
  label,
  sections,
  groups,
  hideHeader,
}: SettingsSidebarProps) => {
  const [search, setSearch] = useState('');

  const query = search.toLowerCase();
  const matchesSearch = (s: SettingsSection) =>
    s.title.toLowerCase().includes(query) || s.description.toLowerCase().includes(query);

  return (
    <div className="flex flex-col h-full overflow-y-auto">
      {!hideHeader && (
        <div className="p-3 pb-2">
          <div className="flex items-center gap-2.5 rounded-lg px-3 py-2 text-sm font-medium bg-duck-teal/15 text-duck-teal">
            <Icon className="h-4 w-4" />
            {label}
          </div>
        </div>
      )}
      <div className="px-3 pb-2">
        <Input
          placeholder="Search..."
          value={search}
          onChange={(ev) => setSearch(ev.target.value)}
          className="h-8 text-xs"
        />
      </div>
      <div className="flex flex-col gap-0.5 px-3 overflow-y-auto flex-1">
        {groups
          ? groups.map((group) => {
              const filtered = group.sections.filter(matchesSearch);
              if (filtered.length === 0) return null;
              return (
                <div key={group.label}>
                  <div className="flex items-center gap-2 px-3 pt-3 pb-1">
                    <group.icon className="h-3 w-3 text-duck-dark/30 dark:text-foreground/30" />
                    <span className="text-[11px] font-semibold uppercase tracking-wider text-duck-dark/30 dark:text-foreground/30">
                      {group.label}
                    </span>
                  </div>
                  {filtered.map((s) => (
                    <SectionLink key={s.key} section={s} to={`${basePath}/${s.key}`} />
                  ))}
                </div>
              );
            })
          : sections
              .filter(matchesSearch)
              .map((s) => <SectionLink key={s.key} section={s} to={`${basePath}/${s.key}`} />)}
      </div>
    </div>
  );
};

type SettingsContentProps = {
  sections: SettingsSection[];
};

export const SettingsContent = ({ sections }: SettingsContentProps) => {
  // The sidebar and this pane are two sibling panels that used to agree via a shared `useGlobal` key.
  // They agree via the URL now, so neither has to be told about the other — and neither can be the one
  // that seeds the slot, which is what made the old defaulting order matter (see §5.6).
  const { section: selectedKey } = useParams<{ section?: string }>();
  const section = sections.find((s) => s.key === selectedKey);

  if (!section) {
    return (
      <div className="h-full flex items-center justify-center">
        <p className="text-sm text-duck-dark/30 dark:text-foreground/30">Select a section</p>
      </div>
    );
  }

  return (
    <div className="h-full overflow-y-auto p-6">
      <div className="flex items-center gap-2.5 mb-1">
        <section.icon className="h-4.5 w-4.5 text-duck-teal shrink-0" />
        <h2 className="text-lg font-bold text-duck-dark dark:text-foreground">{section.title}</h2>
      </div>
      <p className="text-sm text-duck-dark/50 dark:text-foreground/50 mb-6">{section.description}</p>
      <div>{section.content}</div>
    </div>
  );
};

/**
 * The one guard each settings screen renders, per the route-pair convention: it canonicalises both the
 * bare page route and a section that does not exist, so `/settings/ai` and `/settings/ai/nonsense` both
 * land on the first section instead of on "Select a section".
 *
 * Place it after the screen's hooks — it returns early.
 */
type SettingsRouteProps = { basePath: string; sections: SettingsSection[]; children: ReactNode };

export const SettingsRoute = ({ basePath, sections, children }: SettingsRouteProps) => {
  const { section } = useParams<{ section?: string }>();
  const first = sections[0];
  if (first && !sections.some((s) => s.key === section)) return <Navigate to={`${basePath}/${first.key}`} replace />;
  return <>{children}</>;
};

type CreateSettingsPanelParams = {
  basePath: string;
  sidebarIcon: LucideIcon;
  sidebarLabel: string;
  sections?: SettingsSection[];
  groups?: SettingsSectionGroup[];
};

export const createSettingsPanelComponents = ({
  basePath,
  sidebarIcon,
  sidebarLabel,
  sections = [],
  groups,
}: CreateSettingsPanelParams) => {
  const allSections = groups ? groups.flatMap((g) => g.sections) : sections;
  const Sidebar: ComponentType = () => (
    <SettingsSidebar
      basePath={basePath}
      icon={sidebarIcon}
      label={sidebarLabel}
      sections={allSections}
      groups={groups}
    />
  );
  const Content: ComponentType = () => <SettingsContent sections={allSections} />;
  return { Sidebar, Content, allSections };
};
