import { useId, type ChangeEvent, type ReactNode } from "react";
import { Icon } from "./Icon.js";

export type MediaSource = "file" | "url";
export type MediaPreviewKind = "image" | "gif" | "video";

export interface MediaSourceFieldProps {
  label: string;
  kindLabel?: string;
  source: MediaSource;
  url: string;
  fileName?: string | null;
  uploading?: boolean;
  previewSrc?: string | null;
  previewKind?: MediaPreviewKind | null;
  accept?: string;
  fileButtonLabel?: string;
  emptyFileLabel?: string;
  path?: ReactNode;
  hint?: ReactNode;
  error?: ReactNode;
  onSourceChange: (source: MediaSource) => void;
  onUrlChange: (url: string) => void;
  onFileChange: (file?: File) => void | Promise<void>;
}

function inferredPreviewKind(src: string): MediaPreviewKind {
  if (/\.(mp4|webm|mov|m4v|avi|mkv)(\?.*)?$/i.test(src)) return "video";
  if (/\.gif(\?.*)?$/i.test(src)) return "gif";
  return "image";
}

function MediaPreview({ src, kind }: { src: string; kind?: MediaPreviewKind | null }) {
  const resolvedKind = kind ?? inferredPreviewKind(src);
  if (resolvedKind === "video") return <video src={src} autoPlay loop muted playsInline />;
  return <img src={src} alt="" />;
}

export function MediaSourceField({
  label,
  kindLabel = "media",
  source,
  url,
  fileName,
  uploading = false,
  previewSrc,
  previewKind,
  accept = "image/*,video/*",
  fileButtonLabel = "Выберите файл",
  emptyFileLabel = "Файл не выбран",
  path,
  hint,
  error,
  onSourceChange,
  onUrlChange,
  onFileChange,
}: MediaSourceFieldProps) {
  const inputId = useId();
  const displayFileName = uploading ? "Сохраняем в storage..." : (fileName || emptyFileLabel);

  const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => {
    void onFileChange(event.currentTarget.files?.[0]);
    event.currentTarget.value = "";
  };

  return (
    <div className="nodedc-media-field">
      <div className="nodedc-media-field__label-row">
        <span className="nodedc-media-field__label">{label}</span>
        <span className="nodedc-media-field__kind">{kindLabel}</span>
      </div>
      <div className="nodedc-media-control" data-source={source}>
        <div className="nodedc-media-file" hidden={source !== "file"} data-nodedc-media-source-panel="file">
          <label className="nodedc-media-file__button" htmlFor={inputId}>{fileButtonLabel}</label>
          <span className="nodedc-media-file__name" title={displayFileName}>{displayFileName}</span>
          <input id={inputId} type="file" accept={accept} disabled={uploading} onChange={handleFileChange} />
        </div>
        <input
          className="nodedc-media-url"
          type="url"
          value={url}
          hidden={source !== "url"}
          data-nodedc-media-source-panel="url"
          placeholder="https://..."
          autoComplete="off"
          aria-label={`${label}: внешняя ссылка`}
          onChange={(event) => onUrlChange(event.target.value)}
        />
        <div className="nodedc-media-source-switch" aria-label={`${label}: источник`}>
          <button
            type="button"
            className="nodedc-media-source-button"
            data-active={source === "file" ? "true" : undefined}
            data-nodedc-media-source-option="file"
            aria-label="Файл с диска"
            aria-pressed={source === "file"}
            onClick={() => onSourceChange("file")}
          >HD</button>
          <button
            type="button"
            className="nodedc-media-source-button"
            data-active={source === "url" ? "true" : undefined}
            data-nodedc-media-source-option="url"
            aria-label="Внешняя ссылка"
            aria-pressed={source === "url"}
            onClick={() => onSourceChange("url")}
          >URL</button>
        </div>
        <div className="nodedc-media-preview" aria-hidden="true">
          {previewSrc ? <MediaPreview src={previewSrc} kind={previewKind} /> : <Icon name="image" size={16} />}
        </div>
      </div>
      {path ? <span className="nodedc-media-field__path">{path}</span> : null}
      {hint ? <span className="nodedc-media-field__hint">{hint}</span> : null}
      {error ? <span className="nodedc-media-field__error" role="alert">{error}</span> : null}
    </div>
  );
}
