"""FikoYT Audio Concat — 2-4 AUDIO girdisini cross-fade ile birleştir."""
import torch
import torchaudio.functional as F


def _normalize(audio: dict, target_sr: int) -> torch.Tensor:
    """[1, C, S] tensora dönüştür ve gerekirse resample et."""
    if audio is None:
        return None
    wav = audio["waveform"]
    sr = int(audio["sample_rate"])
    if wav.dim() == 2:
        wav = wav.unsqueeze(0)
    if wav.dim() == 1:
        wav = wav.unsqueeze(0).unsqueeze(0)
    if sr != target_sr:
        # batch boyutu var, [B*C, S]'e indir
        b, c, s = wav.shape
        wav = wav.reshape(b * c, s)
        wav = F.resample(wav.float(), sr, target_sr)
        wav = wav.reshape(b, c, -1)
    return wav.float()


def _match_channels(a: torch.Tensor, b: torch.Tensor):
    """İki tensor'ün channel sayısını eşle (mono → stereo veya tersi)."""
    ca, cb = a.shape[1], b.shape[1]
    if ca == cb:
        return a, b
    target = max(ca, cb)
    if ca < target:
        a = a.repeat(1, target // ca, 1)[:, :target, :]
    if cb < target:
        b = b.repeat(1, target // cb, 1)[:, :target, :]
    return a, b


def _crossfade(a: torch.Tensor, b: torch.Tensor, xf_samples: int) -> torch.Tensor:
    if xf_samples <= 0 or a.shape[-1] == 0:
        return torch.cat([a, b], dim=-1)
    xf = min(xf_samples, a.shape[-1], b.shape[-1])
    if xf <= 1:
        return torch.cat([a, b], dim=-1)
    ramp = torch.linspace(0.0, 1.0, xf, device=a.device)
    tail = a[..., -xf:] * (1.0 - ramp) + b[..., :xf] * ramp
    return torch.cat([a[..., :-xf], tail, b[..., xf:]], dim=-1)


class FikoYTAudioConcat:
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {
                "audio_a": ("AUDIO",),
                "audio_b": ("AUDIO",),
                "crossfade_sec": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 10.0, "step": 0.05}),
            },
            "optional": {
                "audio_c": ("AUDIO",),
                "audio_d": ("AUDIO",),
            }
        }

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

    def concat(self, audio_a, audio_b, crossfade_sec, audio_c=None, audio_d=None):
        target_sr = int(audio_a["sample_rate"])
        chunks = [_normalize(a, target_sr) for a in (audio_a, audio_b, audio_c, audio_d) if a is not None]

        xf_samples = int(crossfade_sec * target_sr)
        out = chunks[0]
        for nxt in chunks[1:]:
            out, nxt = _match_channels(out, nxt)
            out = _crossfade(out, nxt, xf_samples)

        print(f"[FikoYT Concat] {len(chunks)} parça → {out.shape[-1]/target_sr:.2f}s @ {target_sr}Hz")
        return ({"waveform": out, "sample_rate": target_sr},)


NODE_CLASS_MAPPINGS = {"FikoYTAudioConcat": FikoYTAudioConcat}
NODE_DISPLAY_NAME_MAPPINGS = {"FikoYTAudioConcat": "FikoYT • Audio Concat (xfade)"}
