"""FikoYT Master Audio — ffmpeg EQ + compressor + limiter zinciri (5 preset)."""
import os
import shutil
import subprocess
import tempfile

import torch
import torchaudio


def _ffmpeg_bin() -> str:
    """Önce imageio-ffmpeg, sonra system PATH."""
    try:
        import imageio_ffmpeg
        return imageio_ffmpeg.get_ffmpeg_exe()
    except Exception:
        pass
    ff = shutil.which("ffmpeg")
    if ff:
        return ff
    raise RuntimeError("ffmpeg bulunamadı — imageio-ffmpeg veya system ffmpeg gerekli.")


# Preset → ffmpeg filter chain template. {lufs} ve {tp} runtime'da formatlanır.
PRESETS = {
    "bright": (
        "highpass=f=30,"
        "equalizer=f=80:t=h:width=2:g=2.5,"
        "equalizer=f=2500:t=h:width=2:g=1.5,"
        "equalizer=f=10000:t=h:width=2:g=2,"
        "acompressor=threshold=0.5:ratio=3:attack=20:release=200:makeup=2,"
        "loudnorm=I={lufs}:LRA=11:TP={tp},"
        "alimiter=limit=0.95"
    ),
    "warm": (
        "equalizer=f=150:t=h:width=2:g=2.5,"
        "equalizer=f=1000:t=h:width=2:g=1.5,"
        "equalizer=f=8000:t=h:width=2:g=-2.5,"
        "acompressor=threshold=0.45:ratio=4:attack=15:release=180:makeup=2.5,"
        "loudnorm=I={lufs}:LRA=11:TP={tp},"
        "alimiter=limit=0.92"
    ),
    "cinematic": (
        "equalizer=f=60:t=h:width=2:g=3,"
        "equalizer=f=200:t=h:width=2:g=1,"
        "equalizer=f=5000:t=h:width=2:g=1.5,"
        "extrastereo=m=1.8,"
        "acompressor=threshold=0.55:ratio=2:attack=30:release=300:makeup=2,"
        "loudnorm=I={lufs}:LRA=14:TP={tp},"
        "alimiter=limit=0.95"
    ),
    "podcast": (
        "highpass=f=80,"
        "equalizer=f=200:t=h:width=2:g=2,"
        "equalizer=f=3000:t=h:width=2:g=2.5,"
        "lowpass=f=12000,"
        "acompressor=threshold=0.35:ratio=4:attack=10:release=150:makeup=3,"
        "loudnorm=I={lufs}:LRA=7:TP={tp},"
        "alimiter=limit=0.95"
    ),
    "loud": (
        "equalizer=f=60:t=h:width=2:g=2,"
        "equalizer=f=4000:t=h:width=2:g=1,"
        "acompressor=threshold=0.3:ratio=6:attack=5:release=120:makeup=4,"
        "loudnorm=I={lufs}:LRA=6:TP={tp},"
        "alimiter=limit=0.98"
    ),
}


class FikoYTMasterAudio:
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {
                "audio": ("AUDIO",),
                "preset": (list(PRESETS.keys()), {"default": "bright"}),
                "target_lufs": ("FLOAT", {"default": -14.0, "min": -30.0, "max": -6.0, "step": 0.1}),
                "true_peak": ("FLOAT", {"default": -1.0, "min": -3.0, "max": 0.0, "step": 0.1}),
            }
        }

    RETURN_TYPES = ("AUDIO",)
    RETURN_NAMES = ("audio",)
    FUNCTION = "master"
    CATEGORY = "FikoYT/audio"

    def master(self, audio, preset, target_lufs, true_peak):
        ff = _ffmpeg_bin()

        wav = audio["waveform"]
        sr = int(audio["sample_rate"])
        was_batched = (wav.dim() == 3)
        wav_for_save = wav.squeeze(0) if was_batched else wav
        if wav_for_save.dim() == 1:
            wav_for_save = wav_for_save.unsqueeze(0)

        tmpdir = tempfile.mkdtemp(prefix="fikoyt_master_")
        in_path = os.path.join(tmpdir, "in.wav")
        out_path = os.path.join(tmpdir, "out.wav")
        torchaudio.save(in_path, wav_for_save.cpu().float(), sr)

        chain = PRESETS[preset].format(lufs=f"{target_lufs:.1f}", tp=f"{true_peak:.1f}")
        cmd = [ff, "-y", "-i", in_path, "-af", chain, "-c:a", "pcm_s16le", out_path]

        print(f"[FikoYT Master] preset={preset} LUFS={target_lufs} TP={true_peak}")
        try:
            proc = subprocess.run(cmd, capture_output=True, timeout=600)
            if proc.returncode != 0:
                err = (proc.stderr or b"").decode("utf-8", errors="replace")[-500:]
                raise RuntimeError(f"ffmpeg hatası: {err}")
        except subprocess.TimeoutExpired:
            raise RuntimeError("ffmpeg 10 dk içinde tamamlanamadı")

        out_wav, out_sr = torchaudio.load(out_path)
        if out_wav.dim() == 2:
            out_wav = out_wav.unsqueeze(0)

        for p in (in_path, out_path):
            try:
                os.remove(p)
            except Exception:
                pass
        try:
            os.rmdir(tmpdir)
        except Exception:
            pass

        return ({"waveform": out_wav.float(), "sample_rate": int(out_sr)},)


NODE_CLASS_MAPPINGS = {"FikoYTMasterAudio": FikoYTMasterAudio}
NODE_DISPLAY_NAME_MAPPINGS = {"FikoYTMasterAudio": "FikoYT • Master Audio (5 preset)"}
