"use client";

import type { ChangeEvent, DragEvent, PropsWithChildren, ReactNode } from "react";
import { useCallback, useId, useRef, useState } from "react";
import clsx from "clsx";
import styles from "./PhotoDropzone.module.css";
import { Icon } from "@/components/ui/Icon";

export type PhotoAsset = {
  id: string;
  name: string;
  src: string;
  size?: number;
};

export type PhotoDropzoneProps = {
  label: string;
  description?: string;
  hint?: string;
  badge?: string;
  value?: PhotoAsset | null;
  onChange: (file: File) => void;
  onRemove?: () => void;
  actions?: ReactNode;
  accept?: string;
  variant?: "default" | "compact";
  disabled?: boolean;
  allowReplace?: boolean;
} & PropsWithChildren;

export function PhotoDropzone({
  label,
  description,
  hint,
  badge,
  value,
  onChange,
  onRemove,
  actions,
  accept = "image/*",
  variant = "default",
  disabled = false,
  allowReplace = true,
  children
}: PhotoDropzoneProps) {
  const inputRef = useRef<HTMLInputElement | null>(null);
  const [isDragging, setDragging] = useState(false);
  const id = useId();

  const handleFiles = useCallback(
    (files: FileList | null) => {
      if (!files || files.length === 0) return;
      const [file] = files;
      if (!file) return;
      onChange(file);
    },
    [onChange]
  );

  const handleInputChange = useCallback(
    (event: ChangeEvent<HTMLInputElement>) => {
      handleFiles(event.currentTarget.files);
      event.currentTarget.value = "";
    },
    [handleFiles]
  );

  const handleDrop = useCallback(
    (event: DragEvent<HTMLLabelElement>) => {
      event.preventDefault();
      if (disabled) return;
      setDragging(false);
      handleFiles(event.dataTransfer.files);
    },
    [disabled, handleFiles]
  );

  const handleDragOver = useCallback((event: DragEvent<HTMLLabelElement>) => {
    event.preventDefault();
    if (disabled) return;
    setDragging(true);
  }, [disabled]);

  const handleDragLeave = useCallback((event: DragEvent<HTMLLabelElement>) => {
    event.preventDefault();
    setDragging(false);
  }, []);

  return (
    <label
      htmlFor={id}
      className={clsx(styles.root)}
      data-variant={variant === "compact" ? "compact" : "default"}
      data-has-image={Boolean(value)}
      data-disabled={disabled}
      onDragOver={handleDragOver}
      onDragLeave={handleDragLeave}
      onDrop={handleDrop}
      style={
        isDragging
          ? {
            borderColor: "rgba(37, 99, 235, 0.55)",
            background: "rgba(59, 130, 246, 0.12)"
          }
          : undefined
      }
    >
      {badge ? <span className={styles.badge}>{badge}</span> : null}
      {!value ? (
        <div className={styles.icon}>
          <Icon name="UploadCloud" />
        </div>
      ) : null}

      <div className={styles.label}>{label}</div>
      {description ? <div className={styles.description}>{description}</div> : null}
      {hint ? (
        <div className={styles.hint}>
          <Icon name="Info" />
          <span>{hint}</span>
        </div>
      ) : null}

      {value ? (
        <div className={variant === "compact" ? styles.compactPreview : styles.preview}>
          <img src={value.src} alt={value.name} loading="lazy" />
        </div>
      ) : null}

      <div className={styles.actions}>
        {allowReplace ? (
          <button
            type="button"
            className={styles.uploadButton}
            onClick={(event) => {
              event.preventDefault();
              if (disabled) return;
              inputRef.current?.click();
            }}
          >
            {value ? "Заменить" : "Загрузить"}
          </button>
        ) : null}
        {value && onRemove ? (
          <button
            type="button"
            className={styles.removeButton}
            onClick={(event) => {
              event.preventDefault();
              onRemove();
            }}
          >
            Удалить
          </button>
        ) : null}
        {actions}
      </div>

      {children}

      <input
        ref={inputRef}
        className={styles.input}
        id={id}
        type="file"
        accept={accept}
        disabled={disabled}
        onChange={handleInputChange}
      />
    </label>
  );
}

