"use client";

import { useCallback, useRef } from "react";
import { UploadOutlined } from "@ant-design/icons";
import { Node, NodeProps } from "@xyflow/react";
import { Spin } from "antd";
import { useI18n } from "@/i18n";
import { useWorkflowStore } from "@/store/workflowStore";
import { SmartAudioNodeData } from "@/types";
import { uploadFileToGatewayMedia } from "@/utils/gatewayMediaUpload";
import { deriveSmartAudioMode } from "@/utils/smartAudioMode";
import { AudioInputNodeView } from "./AudioInputNode";
import { GenerateAudioNodeView } from "./GenerateAudioNode";

type SmartAudioNodeType = Node<SmartAudioNodeData, "smartAudio">;
const MAX_FILE_SIZE = 50 * 1024 * 1024;

function SmartAudioUploadToolbar({
  id,
  selected,
  isUploading,
}: {
  id: string;
  selected?: boolean;
  isUploading: boolean;
}) {
  const { t } = useI18n();
  const updateNodeData = useWorkflowStore((state) => state.updateNodeData);
  const selectSingleNode = useWorkflowStore((state) => state.selectSingleNode);
  const fileInputRef = useRef<HTMLInputElement>(null);

  const applyAudio = useCallback(
    (audioFile: string, filename: string, format: string, duration: number | null) => {
      updateNodeData(id, {
        audioFile,
        audioFileRef: undefined,
        filename,
        format,
        duration,
      });
    },
    [id, updateNodeData]
  );

  const handleFile = useCallback(
    (file: File) => {
      if (!file.type.match(/^audio\//)) {
        alert(t("upload.audioUnsupported"));
        return;
      }

      if (file.size > MAX_FILE_SIZE) {
        alert(t("upload.audioTooLarge"));
        return;
      }

      updateNodeData(id, { uploadStatus: "loading", uploadError: null });

      const metadataUrl = URL.createObjectURL(file);
      const applyUpload = (duration: number | null) => {
        URL.revokeObjectURL(metadataUrl);
        uploadFileToGatewayMedia(file, "audio")
          .then((uploaded) => {
            updateNodeData(id, { uploadStatus: "idle", uploadError: null });
            applyAudio(uploaded.url, uploaded.filename, uploaded.contentType, duration);
          })
          .catch((error) => {
            const message = error instanceof Error ? error.message : "Media upload failed";
            updateNodeData(id, { uploadStatus: "error", uploadError: message });
            alert(message);
          });
      };

      const audio = new Audio(metadataUrl);
      audio.onloadedmetadata = () => applyUpload(Number.isFinite(audio.duration) ? audio.duration : null);
      audio.onerror = () => applyUpload(null);
    },
    [applyAudio, id, t, updateNodeData]
  );

  const handleFileChange = useCallback(
    (event: React.ChangeEvent<HTMLInputElement>) => {
      const file = event.target.files?.[0];
      if (file) handleFile(file);
    },
    [handleFile]
  );

  const handleOpenFileDialog = useCallback(() => {
    if (isUploading) return;
    selectSingleNode(id);
    fileInputRef.current?.click();
  }, [id, isUploading, selectSingleNode]);

  return (
    <>
      <input
        ref={fileInputRef}
        type="file"
        accept="audio/mp3,audio/mpeg,audio/wav,audio/ogg,audio/aac,audio/mp4,audio/*"
        onChange={handleFileChange}
        className="hidden"
      />

      {selected && (
        <div className="nodrag nopan absolute left-1/2 -top-[86px] z-[10002] flex -translate-x-1/2 items-center gap-2">
          <button
            type="button"
            onClick={(event) => {
              event.preventDefault();
              event.stopPropagation();
              handleOpenFileDialog();
            }}
            aria-label={t("imageInput.localUpload")}
            disabled={isUploading}
            className="flex h-10 items-center gap-2 whitespace-nowrap rounded-lg border border-neutral-600/70 bg-neutral-800 px-3 text-sm text-neutral-200 shadow-xl shadow-black/30 transition-colors hover:border-neutral-500 hover:bg-neutral-700 hover:text-neutral-100 disabled:cursor-wait disabled:opacity-60"
          >
            <UploadOutlined className="text-base" />
            <span>{t("imageInput.localUpload")}</span>
          </button>
        </div>
      )}
    </>
  );
}

function SmartAudioEmptyView({
  id,
  data,
  selected,
}: {
  id: string;
  data: SmartAudioNodeData;
  selected?: boolean;
}) {
  const isUploading = data.uploadStatus === "loading";

  return (
    <div className="relative h-full w-full">
      <GenerateAudioNodeView id={id} data={data} selected={selected} />
      <SmartAudioUploadToolbar id={id} selected={selected} isUploading={isUploading} />
      {isUploading && (
        <div className="nodrag nopan absolute inset-0 z-[10003] flex items-center justify-center rounded-lg bg-black/45 backdrop-blur-[1px]">
          <Spin />
        </div>
      )}
    </div>
  );
}

export function SmartAudioNode({ id, data, selected }: NodeProps<SmartAudioNodeType>) {
  const edges = useWorkflowStore((state) => state.edges);
  const mode = deriveSmartAudioMode(id, data, edges);

  if (mode === "generate") {
    return <GenerateAudioNodeView id={id} data={data} selected={selected} />;
  }

  if (mode === "audio") {
    return <AudioInputNodeView id={id} data={data} selected={selected} />;
  }

  return <SmartAudioEmptyView id={id} data={data} selected={selected} />;
}
