"use client";

import * as React from "react";
import { ChevronDownIcon, ChevronUpIcon, InfoIcon, RefreshCwIcon, XIcon } from "lucide-react";

import { Button } from "@/components/ui/button";
import { Sheet, SheetContent, SheetDescription, SheetTitle } from "@/components/ui/sheet";
import { cn } from "@/lib/utils";

import { PanelError } from "./errors";
import { TONE_BOX } from "./tones";
import { useUnsavedChangesGuard } from "./unsaved-changes";

export type DrawerState = "loading" | "ready" | "error";

type Common = {
  /** The record's human name or number ("SALE-005200", "Amoxil 500 mg"), known from the row, so it shows at once. */
  title: string;
  /** Record number, status badge. */
  subtitle?: React.ReactNode;
  /** Header actions: "Open full page", "Edit". */
  actions?: React.ReactNode;
  state?: DrawerState;
  onRetry?: () => void;
  /** Someone else saved this record: show the reload note. */
  changedElsewhere?: boolean;
  onReload?: () => void;
  /** Previous / next record in the list, without closing. Names include the record type ("Next sale"). */
  nav?: { noun: string; onPrev?: () => void; onNext?: () => void; position?: string };
  /** Edit variants: Cancel and Save. */
  footer?: React.ReactNode;
  children: React.ReactNode;
};

function Header({ title, subtitle, actions, nav, onClose, titleId, closeLabel }: Pick<Common, "title" | "subtitle" | "actions" | "nav"> & { onClose: () => void; titleId?: string; closeLabel: string }) {
  return (
    <div className="sticky top-0 z-10 flex items-start gap-2 border-b border-[var(--color-border-subtle)] bg-popover px-4 py-3">
      <div className="min-w-0 flex-1">
        <h2 id={titleId} className="truncate text-lg leading-6 font-semibold">
          {title}
        </h2>
        {subtitle ? <div className="mt-0.5 flex flex-wrap items-center gap-2 text-[13px] text-muted-foreground">{subtitle}</div> : null}
      </div>
      {actions ? <div className="flex items-center gap-1">{actions}</div> : null}
      {nav ? (
        <div className="flex items-center gap-0.5">
          {nav.position ? <span className="mr-1 text-xs text-muted-foreground tabular-nums">{nav.position}</span> : null}
          <Button variant="ghost" size="icon-sm" aria-label={`Previous ${nav.noun}`} onClick={nav.onPrev} disabled={!nav.onPrev}>
            <ChevronUpIcon />
          </Button>
          <Button variant="ghost" size="icon-sm" aria-label={`Next ${nav.noun}`} onClick={nav.onNext} disabled={!nav.onNext}>
            <ChevronDownIcon />
          </Button>
        </div>
      ) : null}
      <Button variant="ghost" size="icon-sm" aria-label={closeLabel} onClick={onClose}>
        <XIcon />
      </Button>
    </div>
  );
}

function Body({ state = "ready", onRetry, changedElsewhere, onReload, children }: Pick<Common, "state" | "onRetry" | "changedElsewhere" | "onReload" | "children">) {
  return (
    <div className="min-h-0 flex-1 overflow-y-auto px-4 py-4">
      {changedElsewhere ? (
        <div className={cn("mb-4 flex items-center gap-2 rounded-lg border px-3 py-2 text-sm", TONE_BOX.info)}>
          <InfoIcon className="size-4 shrink-0" aria-hidden />
          <p className="flex-1">This record was changed by someone else. Reload to see the latest.</p>
          <Button size="xs" variant="outline" className="bg-background" onClick={onReload}>
            <RefreshCwIcon data-icon="inline-start" />
            Reload
          </Button>
        </div>
      ) : null}
      {state === "loading" ? (
        <div className="space-y-3" aria-busy>
          {[60, 90, 75, 85, 40, 70].map((w, i) => (
            <div key={i} className="h-4 animate-pulse rounded-sm bg-muted" style={{ width: `${w}%` }} />
          ))}
        </div>
      ) : state === "error" ? (
        <PanelError what="this record" onRetry={onRetry ?? (() => {})} />
      ) : (
        children
      )}
    </div>
  );
}

/**
 * Drawer (spec 04 §3): work related to the page behind, so the user keeps their place.
 * - `detail` (480 px): read-only; backdrop click closes; Previous / Next move through the list without closing.
 * - `edit` (480 or 720 px): footer Cancel / Save; closing with unsaved changes asks first (Esc, close, Prev/Next).
 * One drawer at a time; opening another record replaces the content. Close returns focus to the opener.
 */
export function RecordDrawer({
  open,
  onOpenChange,
  variant = "detail",
  width = "md",
  dirty = false,
  onDiscard,
  saving = false,
  ...rest
}: Common & {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  variant?: "detail" | "edit";
  width?: "md" | "lg";
  dirty?: boolean;
  onDiscard?: () => void;
  saving?: boolean;
}) {
  const { guard, dialog } = useUnsavedChangesGuard({ dirty: variant === "edit" && dirty, changes: ["your changes to this record"], discard: onDiscard });
  const close = () => {
    if (saving) return;
    guard(() => onOpenChange(false));
  };
  const nav = rest.nav
    ? {
        ...rest.nav,
        onPrev: rest.nav.onPrev ? () => guard(rest.nav!.onPrev!) : undefined,
        onNext: rest.nav.onNext ? () => guard(rest.nav!.onNext!) : undefined,
      }
    : undefined;

  return (
    <>
      <Sheet
        open={open}
        onOpenChange={(o, details) => {
          if (o) return onOpenChange(true);
          // Backdrop clicks close read-only drawers only.
          if (variant === "edit" && details?.reason === "outside-press") return;
          close();
        }}
      >
        <SheetContent
          side="right"
          showCloseButton={false}
          className={cn(
            "gap-0 rounded-l-lg p-0 data-[side=right]:w-[calc(100%-1.5rem)]",
            width === "md" ? "data-[side=right]:sm:max-w-[480px]" : "data-[side=right]:sm:max-w-[720px]",
          )}
        >
          <SheetTitle className="sr-only">{rest.title}</SheetTitle>
          {/* Read out with the title: the drawer's own subtitle when it has one, never a generic "Edit record" */}
          {rest.subtitle ? <SheetDescription className="sr-only">{rest.subtitle}</SheetDescription> : null}
          <Header title={rest.title} subtitle={rest.subtitle} actions={rest.actions} nav={nav} onClose={close} closeLabel="Close" />
          <Body state={rest.state} onRetry={rest.onRetry} changedElsewhere={rest.changedElsewhere} onReload={rest.onReload}>
            {rest.children}
          </Body>
          {rest.footer ? <div className="sticky bottom-0 flex justify-end gap-2 border-t border-[var(--color-border-subtle)] bg-popover px-4 py-3">{rest.footer}</div> : null}
        </SheetContent>
      </Sheet>
      {dialog}
    </>
  );
}

/**
 * Docked master-detail panel (spec 04 §3): sits beside the list inside the content area (no backdrop, no
 * focus trap); the list narrows instead of being covered and stays usable. A labelled region; Esc and
 * "Close panel" both close it. Below 768 px the same content opens as a detail drawer instead.
 */
export function DockedDetail({
  list,
  open,
  onClose,
  label,
  ...rest
}: Common & {
  list: React.ReactNode;
  open: boolean;
  onClose: () => void;
  /** Region name: "Sale SALE-005200 details". */
  label: string;
}) {
  const narrow = React.useSyncExternalStore(
    (cb) => {
      const m = window.matchMedia("(max-width: 767px)");
      m.addEventListener("change", cb);
      return () => m.removeEventListener("change", cb);
    },
    () => window.matchMedia("(max-width: 767px)").matches,
    () => false,
  );
  const regionRef = React.useRef<HTMLElement>(null);

  if (narrow) {
    return (
      <>
        {list}
        <RecordDrawer open={open} onOpenChange={(o) => !o && onClose()} {...rest} />
      </>
    );
  }

  return (
    <div className="flex min-h-0 gap-0">
      <div className="min-w-0 flex-1">{list}</div>
      {open ? (
        <section
          ref={regionRef}
          aria-label={label}
          onKeyDown={(e) => {
            if (e.key === "Escape") {
              e.stopPropagation();
              onClose();
            }
          }}
          className="relative z-[1] flex w-[480px] max-w-[50%] shrink-0 flex-col border-l border-[var(--color-border-panel)] bg-card"
        >
          <Header title={rest.title} subtitle={rest.subtitle} actions={rest.actions} nav={rest.nav} onClose={onClose} closeLabel="Close panel" />
          <Body state={rest.state} onRetry={rest.onRetry} changedElsewhere={rest.changedElsewhere} onReload={rest.onReload}>
            {rest.children}
          </Body>
        </section>
      ) : null}
    </div>
  );
}
