"use client";
import SystemAlert from "@/components/ui/SystemAlert";
import {
  Children,
  isValidElement,
  useId,
  useState,
  type ReactNode,
  type Ref,
  type ComponentProps,
  type InputHTMLAttributes,
  type SelectHTMLAttributes,
  type TextareaHTMLAttributes,
} from "react";
import {
  Button,
  Card,
  Input,
  Label,
  ListBox,
  Select,
  TextArea,
  TextField as HeroTextField,
} from "@heroui/react";
import { Upload, LoaderCircle } from "lucide-react";

export function Field({
  label,
  id,
  required,
  disabled,
  readOnly,
  inputRef,
  ...props
}: InputHTMLAttributes<HTMLInputElement> & { label: string; inputRef?: Ref<HTMLInputElement> }) {
  const generatedId = useId();
  const fieldId = id ?? generatedId;
  return (
    <HeroTextField
      variant="secondary"
      isRequired={required}
      isDisabled={disabled}
      isReadOnly={readOnly}
      className="min-w-0 w-full"
    >
      <Label htmlFor={fieldId}>{label}</Label>
      <Input
        {...props}
        ref={inputRef}
        id={fieldId}
        required={required}
        disabled={disabled}
        readOnly={readOnly}
        variant="secondary"
        fullWidth
      />
    </HeroTextField>
  );
}
export function TextField({
  label,
  id,
  required,
  disabled,
  ...props
}: TextareaHTMLAttributes<HTMLTextAreaElement> & { label: string }) {
  const generatedId = useId();
  const fieldId = id ?? generatedId;
  return (
    <HeroTextField
      variant="secondary"
      isRequired={required}
      isDisabled={disabled}
      className="min-w-0 w-full"
    >
      <Label htmlFor={fieldId}>{label}</Label>
      <TextArea
        rows={4}
        {...props}
        id={fieldId}
        required={required}
        disabled={disabled}
        variant="secondary"
        fullWidth
      />
    </HeroTextField>
  );
}
type SelectProps = Omit<
  SelectHTMLAttributes<HTMLSelectElement>,
  "onChange" | "value" | "defaultValue"
> & {
  label: string;
  value?: string | number;
  defaultValue?: string | number;
  onChange?: (event: { target: { value: string } }) => void;
};
export function SelectField({
  label,
  children,
  value,
  defaultValue,
  onChange,
  name,
  disabled,
  required,
}: SelectProps) {
  const options = Children.toArray(children)
    .filter(isValidElement)
    .map((child) => {
      const option = child.props as { value?: string | number; children?: ReactNode };
      return { value: String(option.value ?? ""), label: String(option.children ?? "") };
    });
  const [localValue, setLocalValue] = useState(String(defaultValue ?? options[0]?.value ?? ""));
  const selected = value === undefined ? localValue : String(value);
  return (
    <Select
      aria-label={label}
      className="min-w-0 w-full"
      variant="secondary"
      isDisabled={disabled}
      isRequired={required}
      value={selected || "__none__"}
      onChange={(key) => {
        const next = key === "__none__" || key === null ? "" : String(key);
        setLocalValue(next);
        onChange?.({ target: { value: next } });
      }}
    >
      <Label>{label}</Label>
      <Select.Trigger>
        <Select.Value />
        <Select.Indicator />
      </Select.Trigger>
      <Select.Popover>
        <ListBox>
          {options.map((option) => (
            <ListBox.Item
              key={option.value || "__none__"}
              id={option.value || "__none__"}
              textValue={option.label}
            >
              {option.label}
              <ListBox.ItemIndicator />
            </ListBox.Item>
          ))}
        </ListBox>
      </Select.Popover>
      {name && <input type="hidden" name={name} value={selected} />}
    </Select>
  );
}
export function ActionButton({
  children,
  primary = false,
  className = "",
  disabled,
  ...props
}: Omit<ComponentProps<typeof Button>, "isDisabled" | "className"> & {
  disabled?: boolean;
  primary?: boolean;
  className?: string;
}) {
  return (
    <Button
      type="button"
      {...props}
      isDisabled={disabled}
      variant="secondary"
      className={
        "min-h-10 rounded-full " +
        (primary ? "bg-[#9d2449] !text-white hover:bg-[#801c3a] " : "") +
        className
      }
    >
      {children}
    </Button>
  );
}
export function IconActionButton(
  props: Omit<ComponentProps<typeof ActionButton>, "primary"> & { "aria-label": string },
) {
  return <ActionButton {...props} />;
}
export function Panel({
  title,
  children,
  action,
}: {
  title: string;
  children: ReactNode;
  action?: ReactNode;
}) {
  return (
    <Card className="min-w-0 gap-0 border border-zinc-200/80 p-5 shadow-none sm:p-6">
      <Card.Header className="mb-5 flex flex-row flex-wrap items-center justify-between gap-3 p-0">
        <Card.Title className="text-lg font-semibold text-zinc-900">{title}</Card.Title>
        {action}
      </Card.Header>
      <Card.Content className="min-w-0 p-0">{children}</Card.Content>
    </Card>
  );
}
export function fileHref(aulaId: number, url: string) {
  return url.startsWith("/uploads/")
    ? `/api/aulas/${aulaId}/recurso?url=${encodeURIComponent(url)}`
    : url;
}
export type UploadedFile = { url: string; filename: string; size: number; type: string };
export function FileUpload({
  aulaId,
  category,
  label,
  onUploaded,
  onBusy,
}: {
  aulaId: number;
  category: "video" | "material" | "tarea";
  label: string;
  onUploaded: (file: UploadedFile) => void;
  onBusy?: (busy: boolean) => void;
}) {
  const [progress, setProgress] = useState<number | null>(null);
  const [error, setError] = useState("");
  function upload(file?: File) {
    if (!file) return;
    const max = (category === "video" ? 512 : 30) * 1024 * 1024;
    if (file.size > max || !file.size) {
      setError(`Selecciona un archivo de hasta ${category === "video" ? 512 : 30} MB.`);
      return;
    }
    setError("");
    setProgress(0);
    onBusy?.(true);
    const xhr = new XMLHttpRequest();
    xhr.open(
      "POST",
      `/api/aulas/${aulaId}/archivos?tipo=${category}&nombre=${encodeURIComponent(file.name)}`,
    );
    xhr.setRequestHeader("Content-Type", "application/octet-stream");
    xhr.upload.onprogress = (event) => {
      if (event.lengthComputable)
        setProgress(Math.min(99, Math.round((event.loaded / event.total) * 100)));
    };
    const finish = () => {
      setProgress(null);
      onBusy?.(false);
    };
    xhr.onload = () => {
      try {
        const data = JSON.parse(xhr.responseText);
        if (xhr.status >= 200 && xhr.status < 300) onUploaded(data);
        else setError(data.error || "No fue posible cargar el archivo.");
      } catch {
        setError("Respuesta de carga inválida.");
      } finally {
        finish();
      }
    };
    xhr.onerror = () => {
      setError("Error de conexión. Vuelve a intentarlo.");
      finish();
    };
    xhr.send(file);
  }
  return (
    <div className="space-y-2">
      <label
        className="flex cursor-pointer flex-col items-center gap-2 rounded-xl border border-dashed border-zinc-300 bg-zinc-50 p-4 text-center text-sm text-zinc-600 transition-colors hover:border-[#9d2449]"
        onDragOver={(e) => e.preventDefault()}
        onDrop={(e) => {
          e.preventDefault();
          if (progress === null) upload(e.dataTransfer.files[0]);
        }}
      >
        {progress === null ? (
          <Upload className="size-5 text-[#9d2449]" aria-hidden="true" />
        ) : (
          <LoaderCircle
            className="size-5 animate-spin motion-reduce:animate-none"
            aria-hidden="true"
          />
        )}
        <span>{progress === null ? label : `Subiendo: ${progress}%`}</span>
        <span className="text-xs text-zinc-400">
          {category === "video"
            ? "MP4, WebM, MOV · Hasta 512 MB"
            : "Documentos, imágenes y ZIP · Hasta 30 MB"}
        </span>
        <input
          aria-label={label}
          type="file"
          disabled={progress !== null}
          accept={
            category === "video"
              ? ".mp4,.webm,.mov,.m4v,.ogg"
              : ".pdf,.zip,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.csv,.jpg,.jpeg,.png,.webp,.mp3"
          }
          className="max-w-full text-xs"
          onChange={(e) => {
            upload(e.target.files?.[0]);
            e.target.value = "";
          }}
        />
      </label>
      {error && (
        <SystemAlert status="danger" title="No se pudo cargar el archivo">
          {error}
        </SystemAlert>
      )}
    </div>
  );
}
