import { useId, useState } from "react";
import type {
  ButtonHTMLAttributes,
  AnchorHTMLAttributes,
  InputHTMLAttributes,
  ReactNode,
} from "react";

export function Button({
  variant = "primary",
  className = "",
  type = "button",
  ...props
}: ButtonHTMLAttributes<HTMLButtonElement> & {
  variant?: "primary" | "secondary" | "text";
}) {
  return (
    <button
      type={type}
      className={`ds-button ds-button--${variant} ${className}`}
      {...props}
    />
  );
}

export function ButtonLink({
  variant = "text",
  className = "",
  ...props
}: AnchorHTMLAttributes<HTMLAnchorElement> & {
  variant?: "primary" | "secondary" | "text";
}) {
  return <a className={`ds-button ds-button--${variant} ${className}`} {...props} />;
}

export function SectionHeading({
  number,
  title,
  children,
  id,
}: {
  number?: string;
  title: ReactNode;
  children?: ReactNode;
  id?: string;
}) {
  return (
    <header className="ds-section-heading">
      {number && <span className="ds-eyebrow">{number}</span>}
      <h2 id={id} tabIndex={-1}>{title}</h2>
      {children && <p>{children}</p>}
    </header>
  );
}

export function Checkbox({
  label,
  description,
  hideLabel = false,
  className = "",
  ...props
}: Omit<InputHTMLAttributes<HTMLInputElement>, "type"> & { label: string; description?: string; hideLabel?: boolean }) {
  const descriptionId = useId();
  return (
    <label className={`ds-checkbox ${className}`}>
      <input
        type="checkbox"
        aria-label={description || hideLabel ? label : undefined}
        {...props}
        aria-describedby={[props["aria-describedby"], description ? descriptionId : undefined].filter(Boolean).join(" ") || undefined}
      />
      <span className={`ds-checkbox-copy${hideLabel ? " ds-visually-hidden" : ""}`}>
        <span className="ds-checkbox-label">{label}</span>
        {description && <span id={descriptionId} className="ds-checkbox-description">{description}</span>}
      </span>
    </label>
  );
}

export function Counter({
  label,
  value,
  target,
  onChange,
  disabled = false,
}: {
  label: string;
  value: number;
  target: number;
  onChange: (value: number) => void;
  disabled?: boolean;
}) {
  const hintId = useId();
  const [edit, setEdit] = useState({ source: value, label, text: String(value) });
  // A changed day or refreshed server total replaces an unsubmitted draft.
  const refreshed = edit.source !== value || edit.label !== label;
  if (refreshed) setEdit({ source: value, label, text: String(value) });
  const draft = refreshed ? String(value) : edit.text;
  const changed = draft !== String(value);
  const maximum = 1_000_000_000;
  const valid = /^\d+$/.test(draft) && Number(draft) <= maximum;
  const updateDraft = (text: string) => setEdit({ source: value, label, text });
  const save = () => {
    if (!disabled && changed && valid) {
      updateDraft(String(Number(draft)));
      onChange(Number(draft));
    }
  };

  return (
    <div className="ds-counter" role="group" aria-label={label}>
      <Button
        variant="text"
        aria-label={`Decrease ${label}`}
        disabled={disabled || value <= 0}
        onClick={() => { updateDraft(String(value)); onChange(Math.max(0, value - 1)); }}
      >
        −
      </Button>
      <input
        className="ds-counter-input"
        type="text"
        inputMode="numeric"
        aria-label={`Total ${label}`}
        aria-describedby={changed && !valid ? hintId : undefined}
        aria-invalid={changed && !valid ? true : undefined}
        title="Enter a total and press Enter to save. Escape cancels."
        value={draft}
        disabled={disabled}
        onChange={event => updateDraft(event.target.value)}
        onKeyDown={event => {
          if (event.key === "Enter") { event.preventDefault(); save(); }
          if (event.key === "Escape") { event.preventDefault(); updateDraft(String(value)); }
        }}
      />
      <span className="ds-muted"> / {target}</span>
      <Button
        variant="text"
        aria-label={`Increase ${label}`}
        disabled={disabled || value >= maximum}
        onClick={() => { updateDraft(String(value)); onChange(Math.min(maximum, value + 1)); }}
      >
        +
      </Button>
      {changed && <Button className="ds-counter-save" variant="secondary" disabled={disabled || !valid} onClick={save} aria-label={`Save total ${label}`}>Save</Button>}
      {changed && !valid && <span className="ds-counter-error" id={hintId} role="alert">Enter a whole number from 0 to 1,000,000,000.</span>}
    </div>
  );
}

export function HabitRow({
  name,
  description,
  complete,
  children,
  tasks,
}: {
  name: string;
  description: string;
  complete: boolean;
  children: ReactNode;
  tasks?: ReactNode;
}) {
  return (
    <div className="ds-habit-row">
      <div className="ds-habit-main">
        <div>
          <h4>{name}</h4>
          <p>{description}</p>
        </div>
        <div className="ds-habit-control">
          {children}
          <span className="ds-status">
            {complete ? "Complete" : "In progress"}
          </span>
        </div>
      </div>
      {tasks && <div className="ds-task-list">{tasks}</div>}
    </div>
  );
}
