import { Button } from "@minmon/ui/components/button";
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from "@minmon/ui/components/card";
import { Input } from "@minmon/ui/components/input";
import { Label } from "@minmon/ui/components/label";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@minmon/ui/components/select";
import { StatusBadge } from "@minmon/ui/components/status-badge";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
  TableWrapper,
} from "@minmon/ui/components/table";
import { Textarea } from "@minmon/ui/components/textarea";
import { Link } from "@tanstack/react-router";
import { Check, ChevronRight, Trash2 } from "lucide-react";
import { useEffect, useState, type ReactNode } from "react";

type BadgeVariant = "neutral" | "success" | "warning" | "destructive" | "info";

export function PageSection({ title, description, action, children }: SectionProps) {
  return (
    <section className="grid gap-4">
      <div className="flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between">
        <div className="space-y-1">
          <h2 className="text-lg font-semibold tracking-tight">{title}</h2>
          {description ? <p className="text-sm text-muted-foreground">{description}</p> : null}
        </div>
        {action ? <div>{action}</div> : null}
      </div>
      {children}
    </section>
  );
}

export function SummaryCard({
  label,
  value,
  hint,
  status,
}: {
  label: string;
  value: string;
  hint: string;
  status?: { label: string; variant: BadgeVariant };
}) {
  return (
    <Card>
      <CardHeader>
        <CardDescription>{label}</CardDescription>
        {status ? <StatusBadge variant={status.variant}>{status.label}</StatusBadge> : null}
      </CardHeader>
      <CardContent className="space-y-2">
        <p className="text-2xl font-semibold tracking-tight">{value}</p>
        <p className="text-sm text-muted-foreground">{hint}</p>
      </CardContent>
    </Card>
  );
}

export function ResourceListCard<TItem extends { id: string }>({
  title,
  description,
  columns,
  items,
  emptyTitle,
  emptyDescription,
}: {
  title: string;
  description: string;
  columns: { key: string; header: string; render: (item: TItem) => ReactNode; className?: string }[];
  items: TItem[];
  emptyTitle: string;
  emptyDescription: string;
}) {
  return (
    <Card className="py-0 pt-4 gap-0">
      <CardHeader className="border-b">
        <CardTitle>{title}</CardTitle>
        <CardDescription>{description}</CardDescription>
      </CardHeader>
      <CardContent className="px-0">
        {items.length ? (
          <TableWrapper className="border-0">
            <Table>
              <TableHeader>
                <TableRow className="hover:bg-transparent">
                  {columns.map((column) => (
                    <TableHead key={column.key} className={column.className}>
                      {column.header}
                    </TableHead>
                  ))}
                </TableRow>
              </TableHeader>
              <TableBody>
                {items.map((item) => (
                  <TableRow key={item.id}>
                    {columns.map((column) => (
                      <TableCell key={column.key} className={column.className}>
                        {column.render(item)}
                      </TableCell>
                    ))}
                  </TableRow>
                ))}
              </TableBody>
            </Table>
          </TableWrapper>
        ) : (
          <EmptyState title={emptyTitle} description={emptyDescription} className="border-0" />
        )}
      </CardContent>
    </Card>
  );
}

export function DetailCard({
  title,
  description,
  rows,
}: {
  title: string;
  description: string;
  rows: { label: string; value: ReactNode }[];
}) {
  return (
    <Card>
      <CardHeader>
        <CardTitle>{title}</CardTitle>
        <CardDescription>{description}</CardDescription>
      </CardHeader>
      <CardContent className="grid gap-4 sm:grid-cols-2">
        {rows.map((row) => (
          <div key={row.label} className="space-y-1 border-l-2 border-border pl-3">
            <p className="text-[11px] uppercase tracking-[0.16em] text-muted-foreground">{row.label}</p>
            <div className="text-sm">{row.value}</div>
          </div>
        ))}
      </CardContent>
    </Card>
  );
}

export function FormCard({
  title,
  description,
  children,
  footer,
}: {
  title: string;
  description: string;
  children: ReactNode;
  footer?: ReactNode;
}) {
  return (
    <Card>
      <CardHeader>
        <CardTitle>{title}</CardTitle>
        <CardDescription>{description}</CardDescription>
      </CardHeader>
      <CardContent className="grid gap-4">{children}</CardContent>
      {footer ? <CardFooter className="justify-between gap-3">{footer}</CardFooter> : null}
    </Card>
  );
}

type FieldError = string | { message?: string } | null | undefined;

function normalizeFieldErrors(errors?: FieldError[]): string[] {
  if (!errors?.length) return [];
  return errors
    .map((err) => {
      if (!err) return null;
      if (typeof err === "string") return err;
      return err.message ?? null;
    })
    .filter((msg): msg is string => Boolean(msg && msg.trim()));
}

export function FieldGroup({
  label,
  htmlFor,
  description,
  errors,
  children,
}: {
  label: string;
  htmlFor: string;
  description?: string;
  errors?: FieldError[];
  children: ReactNode;
}) {
  const messages = normalizeFieldErrors(errors);
  const hasError = messages.length > 0;
  const descriptionId = description ? `${htmlFor}-description` : undefined;
  const errorId = hasError ? `${htmlFor}-error` : undefined;

  return (
    <div className="grid gap-2">
      <Label htmlFor={htmlFor}>{label}</Label>
      {children}
      {description ? (
        <p id={descriptionId} className="text-xs text-muted-foreground">
          {description}
        </p>
      ) : null}
      {hasError ? (
        <p id={errorId} className="text-xs text-destructive" role="alert">
          {messages.join(", ")}
        </p>
      ) : null}
    </div>
  );
}

function describedBy(...ids: (string | undefined)[]): string | undefined {
  const filtered = ids.filter((id): id is string => Boolean(id));
  return filtered.length ? filtered.join(" ") : undefined;
}

export function TextField(
  props: React.ComponentProps<typeof Input> & {
    label: string;
    description?: string;
    errors?: FieldError[];
  },
) {
  const { label, description, errors, id, ...inputProps } = props;
  const fieldId = id ?? inputProps.name ?? label;
  const messages = normalizeFieldErrors(errors);
  const hasError = messages.length > 0;
  const descriptionId = description ? `${fieldId}-description` : undefined;
  const errorId = hasError ? `${fieldId}-error` : undefined;

  return (
    <FieldGroup label={label} htmlFor={fieldId} description={description} errors={errors}>
      <Input
        id={fieldId}
        aria-invalid={hasError || undefined}
        aria-describedby={describedBy(descriptionId, errorId)}
        {...inputProps}
      />
    </FieldGroup>
  );
}

export function TextAreaField(
  props: React.ComponentProps<typeof Textarea> & {
    label: string;
    description?: string;
    errors?: FieldError[];
  },
) {
  const { label, description, errors, id, ...textareaProps } = props;
  const fieldId = id ?? textareaProps.name ?? label;
  const messages = normalizeFieldErrors(errors);
  const hasError = messages.length > 0;
  const descriptionId = description ? `${fieldId}-description` : undefined;
  const errorId = hasError ? `${fieldId}-error` : undefined;

  return (
    <FieldGroup label={label} htmlFor={fieldId} description={description} errors={errors}>
      <Textarea
        id={fieldId}
        aria-invalid={hasError || undefined}
        aria-describedby={describedBy(descriptionId, errorId)}
        {...textareaProps}
      />
    </FieldGroup>
  );
}

export function SelectField({
  label,
  description,
  errors,
  id,
  name,
  value,
  onValueChange,
  onBlur,
  placeholder,
  options,
}: {
  label: string;
  description?: string;
  errors?: FieldError[];
  id?: string;
  name?: string;
  value: string;
  onValueChange: (value: string) => void;
  onBlur?: React.FocusEventHandler<HTMLButtonElement>;
  placeholder?: string;
  options: { value: string; label: string }[];
}) {
  const fieldId = id ?? name ?? label;
  const selectedOption = options.find((option) => option.value === value);
  const messages = normalizeFieldErrors(errors);
  const hasError = messages.length > 0;
  const descriptionId = description ? `${fieldId}-description` : undefined;
  const errorId = hasError ? `${fieldId}-error` : undefined;

  return (
    <FieldGroup label={label} htmlFor={fieldId} description={description} errors={errors}>
      <Select name={name} value={value} onValueChange={(nextValue) => onValueChange(nextValue ?? "")}>
        <SelectTrigger
          id={fieldId}
          className="w-full"
          onBlur={onBlur}
          aria-invalid={hasError || undefined}
          aria-describedby={describedBy(descriptionId, errorId)}
        >
          <SelectValue placeholder={placeholder ?? "Select an option"}>
            {selectedOption?.label}
          </SelectValue>
        </SelectTrigger>
        <SelectContent>
          {options.map((option) => (
            <SelectItem key={option.value} value={option.value}>
              {option.label}
            </SelectItem>
          ))}
        </SelectContent>
      </Select>
    </FieldGroup>
  );
}

export function ConfirmDeleteIconButton({
  itemLabel,
  onConfirm,
  disabled,
}: {
  itemLabel: string;
  onConfirm: () => void;
  disabled?: boolean;
}) {
  const [isConfirming, setIsConfirming] = useState(false);

  useEffect(() => {
    if (!isConfirming) {
      return;
    }

    const timeoutId = window.setTimeout(() => {
      setIsConfirming(false);
    }, 4000);

    return () => {
      window.clearTimeout(timeoutId);
    };
  }, [isConfirming]);

  useEffect(() => {
    if (disabled) {
      setIsConfirming(false);
    }
  }, [disabled]);

  return (
    <div className="flex justify-center">
      <Button
        type="button"
        variant={isConfirming ? "destructive" : "ghost"}
        size="icon"
        className="size-8"
        disabled={disabled}
        aria-label={isConfirming ? `Confirm delete ${itemLabel}` : `Delete ${itemLabel}`}
        onBlur={() => setIsConfirming(false)}
        onClick={() => {
          if (isConfirming) {
            onConfirm();
            setIsConfirming(false);
            return;
          }

          setIsConfirming(true);
        }}
      >
        {isConfirming ? <Check /> : <Trash2 />}
        <span className="sr-only">{isConfirming ? `Confirm delete ${itemLabel}` : `Delete ${itemLabel}`}</span>
      </Button>
    </div>
  );
}

export function EmptyState({
  title,
  description,
  action,
  icon,
  className,
}: {
  title: string;
  description: string;
  action?: ReactNode;
  icon?: ReactNode;
  className?: string;
}) {
  return (
    <div className={"border px-4 py-10 text-center " + (className ?? "")}>
      {icon ? (
        <div className="mx-auto mb-3 flex size-10 items-center justify-center rounded-full bg-muted text-muted-foreground">
          {icon}
        </div>
      ) : null}
      <p className="text-sm font-medium">{title}</p>
      <p className="mx-auto mt-2 max-w-lg text-sm text-muted-foreground">{description}</p>
      {action ? <div className="mt-4 flex justify-center">{action}</div> : null}
    </div>
  );
}

export function QueryStateCard({
  title,
  description,
  action,
}: {
  title: string;
  description: string;
  action?: ReactNode;
}) {
  return <EmptyState title={title} description={description} action={action} />;
}

export function SectionLinks({ items }: { items: { label: string; to: string; detail: string }[] }) {
  return (
    <div className="grid gap-3 md:grid-cols-2 xl:grid-cols-4">
      {items.map((item) => (
        <Link key={item.to} to={item.to} className="border bg-card p-4 transition-colors hover:bg-muted/30">
          <div className="flex items-center justify-between gap-3">
            <div>
              <p className="text-sm font-medium">{item.label}</p>
              <p className="mt-1 text-xs text-muted-foreground">{item.detail}</p>
            </div>
            <ChevronRight className="size-4 text-muted-foreground" />
          </div>
        </Link>
      ))}
    </div>
  );
}

export function FormActions({ cancelTo, submitLabel }: { cancelTo: string; submitLabel: string }) {
  return (
    <>
      <Link to={cancelTo}>
        <Button variant="ghost">Cancel</Button>
      </Link>
      <Button type="submit">{submitLabel}</Button>
    </>
  );
}

interface SectionProps {
  title: string;
  description?: string;
  action?: ReactNode;
  children: ReactNode;
}
