#!/opt/homebrew/bin/python3.11
"""
Weather Sound Detector (Rain & Thunder)
職責：使用聲學特徵 (Librosa) 辨識雨聲 (Rain) 與雷聲 (Thunder)。
"""

import librosa
import numpy as np
import os
import json

# 設定
UUID = os.getenv("UUID", "384b0ff44aaaa1f1")
OUTPUT_DIR = os.getenv("MOMENTRY_OUTPUT_DIR", "./output")
AUDIO_PATH = os.path.join(OUTPUT_DIR, UUID, f"{UUID}.wav")
OUTPUT_JSON = os.path.join(OUTPUT_DIR, UUID, f"{UUID}.weather_events.json")


def detect_weather_sounds(audio_path):
    print(f"🔍 Loading audio: {audio_path}")
    # 使用 16kHz 取樣
    y, sr = librosa.load(audio_path, sr=16000, mono=True)
    total_dur = len(y) / sr

    # 分析視窗：每 10 秒一幀
    hop_length = int(10.0 * sr)
    frame_length = int(10.0 * sr)

    print("📊 Analyzing spectral features...")

    # 1. 計算聲學特徵
    # RMS: 能量 (響度) - shape (1, frames) -> take [0] to get (frames,)
    rms = librosa.feature.rms(y=y, frame_length=frame_length, hop_length=hop_length)[0]

    # Spectral Flatness: 頻譜平坦度 - shape (1, frames) -> take [0]
    flatness = librosa.feature.spectral_flatness(
        y=y, n_fft=frame_length, hop_length=hop_length
    )[0]

    # Spectral Centroid: 頻譜質心 - shape (1, frames) -> take [0]
    centroid = librosa.feature.spectral_centroid(
        y=y, sr=sr, n_fft=frame_length, hop_length=hop_length
    )[0]

    # Low Frequency Energy (LFE): 低頻能量 (計算 < 200Hz 的能量比例)
    L = 200
    n_bins = int(L * frame_length / sr)
    stft = np.abs(librosa.stft(y, n_fft=frame_length, hop_length=hop_length))
    lfe = np.sum(stft[:n_bins, :], axis=0) / (np.sum(stft, axis=0) + 1e-10)

    print("🕵️‍♂️ Scanning for patterns...")

    weather_events = []

    # 滑動檢查
    for i in range(len(rms)):
        t = i * hop_length / sr
        t_end = t + 10.0

        r = rms[i]
        f = flatness[i]
        c = centroid[i]
        l = lfe[i] if i < len(lfe) else 0

        event_type = None
        reason = ""

        # 1. 雷聲偵測 (Thunder)
        # 特徵：高能量 (響) + 低頻能量極高 (轟鳴)
        if r > 0.08 and l > 0.4:
            # 必須是低頻為主，且夠響
            event_type = "Thunder"
            reason = f"High LFE ({l:.2f}) & Loud"

        # 2. 雨聲偵測 (Rain)
        # 特徵：高平坦度 (噪音) + 持續能量 + 中頻質心
        elif f > 0.30 and r > 0.015:
            # 排除純靜音 (r 很低時 flatness 不準)
            # 排除極低頻 (可能是風聲或空轉)
            if 800 < c < 3000:
                event_type = "Rain"
                reason = f"High Flatness ({f:.2f}) & Mid Centroid"

        if event_type:
            weather_events.append(
                {
                    "start": round(t, 1),
                    "end": round(t_end, 1),
                    "type": event_type,
                    "confidence": round(r + l + f, 4),  # 簡單的綜合信心分數
                    "reason": reason,
                }
            )

    return weather_events


if __name__ == "__main__":
    if not os.path.exists(AUDIO_PATH):
        print(f"❌ No audio found at {AUDIO_PATH}")
        exit()

    print(f"🌦️ Starting Weather Sound Analysis for {UUID}...")
    events = detect_weather_sounds(AUDIO_PATH)

    # 合併連續片段 (例如連續 3 個雨聲 -> 1 個大雨聲)
    merged_events = []
    for ev in events:
        if not merged_events:
            merged_events.append(ev)
            continue

        last = merged_events[-1]
        # 如果同類型且時間重疊/相鄰 (間隔 < 5秒)
        if ev["type"] == last["type"] and (ev["start"] - last["end"]) < 5.0:
            last["end"] = ev["end"]
            last["confidence"] = max(last["confidence"], ev["confidence"])
        else:
            merged_events.append(ev)

    print("\n🎉 Analysis Complete!")
    print(f"✅ Found {len(merged_events)} weather segments.")

    # 統計
    rain_count = sum(1 for e in merged_events if e["type"] == "Rain")
    thunder_count = sum(1 for e in merged_events if e["type"] == "Thunder")
    print(f"   🌧️ Rain events: {rain_count}")
    print(f"   ⚡ Thunder events: {thunder_count}")

    # 儲存
    with open(OUTPUT_JSON, "w") as f:
        json.dump({"weather_events": merged_events}, f, indent=2)

    # 顯示 Top 20
    print("\n🔥 Top Weather Moments (Sorted by Confidence):")
    sorted_ev = sorted(merged_events, key=lambda x: x["confidence"], reverse=True)
    for i, ev in enumerate(sorted_ev[:20]):
        m, s = divmod(ev["start"], 60)
        print(f"  {i + 1:02d}. [{int(m):02d}:{s:05.2f}] {ev['type']} ({ev['reason']})")
