# -*- coding: utf-8 -*-
"""
bdf_analyzer.py

Analyze .bdf files - print data amplitude range and mean values.
Supports single file or batch processing of all .bdf files in a directory.
"""
import os
import glob
import numpy as np
import mne
import scipy.signal as signal


def analyze_bdf(filepath: str, unit: str = "uV") -> dict:
    """
    Analyze a single .bdf file and compute statistics.

    Parameters
    ----------
    filepath : str
        Path to .bdf file
    unit : str, optional
        Display unit (default: uV for microvolts)

    Returns
    -------
    dict
        Dictionary containing statistics
    """
    print("=" * 60)
    print(f"File: {os.path.basename(filepath)}")
    print("=" * 60)

    try:
        # Read BDF file
        raw = mne.io.read_raw_bdf(filepath, preload=True, verbose=False)

        # Get data (n_channels, n_times) in V
        data = raw.get_data()
        n_channels, n_times = data.shape
        sfreq = raw.info["sfreq"]

        # Convert to microvolts (uV)
        data_uv = data * 1e6

        # Raw data statistics (V)
        raw_all = data.flatten()
        raw_min = float(np.min(raw_all))
        raw_max = float(np.max(raw_all))
        raw_mean = float(np.mean(raw_all))
        raw_std = float(np.std(raw_all))

        # Overall statistics
        all_values = data_uv.flatten()
        min_val = np.min(all_values)
        max_val = np.max(all_values)
        mean_val = np.mean(all_values)
        std_val = np.std(all_values)

        print(f"Sampling rate: {sfreq:.2f} Hz")
        print(f"Channels:      {n_channels}")
        print(f"Samples:       {n_times:,}")
        print(f"Duration:      {n_times / sfreq:.2f} sec")
        print("-" * 40)
        print(f"[RAW - V]")
        print(f"Amplitude range: [{raw_min:.6f}, {raw_max:.6f}] V")
        print(f"Mean value:      {raw_mean:.6f} V")
        print(f"Std deviation:  {raw_std:.6f} V")
        print(f"[RAW - uV]")
        print(f"Amplitude range: [{min_val:.4f}, {max_val:.4f}] uV")
        print(f"Mean value:      {mean_val:.4f} uV")
        print(f"Std deviation:  {std_val:.4f} uV")
        print("-" * 40)

        # Per-channel statistics
        print("\nPer-channel statistics:")
        print(f"{'Channel':<15} {'Min (uV)':<15} {'Max (uV)':<15} {'Mean (uV)':<15} {'PSD Peak (Hz)':<15}")
        print("-" * 75)

        channel_stats = []
        for i, ch_name in enumerate(raw.ch_names):
            ch_data = data_uv[i, :]
            ch_min = np.min(ch_data)
            ch_max = np.max(ch_data)
            ch_mean = np.mean(ch_data)

            # PSD peak frequency
            nperseg = min(1024, n_times)
            freqs, pxx = signal.welch(ch_data, fs=sfreq, nperseg=nperseg)
            peak_idx = np.argmax(pxx)
            peak_freq = freqs[peak_idx]

            print(f"{ch_name:<15} {ch_min:<15.4f} {ch_max:<15.4f} {ch_mean:<15.4f} {peak_freq:<15.2f}")
            channel_stats.append({
                "name": ch_name,
                "min": ch_min,
                "max": ch_max,
                "mean": ch_mean,
                "psd_peak_hz": peak_freq
            })

        print("=" * 60)
        print()

        return {
            "filepath": filepath,
            "sfreq": sfreq,
            "n_channels": n_channels,
            "n_times": n_times,
            "duration": n_times / sfreq,
            "raw_min": raw_min,
            "raw_max": raw_max,
            "raw_mean": raw_mean,
            "raw_std": raw_std,
            "min": min_val,
            "max": max_val,
            "mean": mean_val,
            "std": std_val,
            "channels": channel_stats
        }

    except Exception as e:
        print(f"[ERROR] Failed to read file: {e}")
        return None


def analyze_directory(dir_path: str) -> list:
    """
    Analyze all .bdf files in a directory.

    Parameters
    ----------
    dir_path : str
        Directory path

    Returns
    -------
    list
        List of analysis results for all files
    """
    # Find all .bdf files
    bdf_files = sorted(glob.glob(os.path.join(dir_path, "*.bdf")))

    if not bdf_files:
        print(f"[WARNING] No .bdf files found in: {dir_path}")
        return []

    print(f"Found {len(bdf_files)} .bdf file(s)\n")

    results = []
    for filepath in bdf_files:
        result = analyze_bdf(filepath)
        if result:
            results.append(result)

    # Summary statistics
    if results:
        print("\n" + "=" * 60)
        print("Summary")
        print("=" * 60)

        all_means = [r["mean"] for r in results]
        all_mins = [r["min"] for r in results]
        all_maxs = [r["max"] for r in results]

        print(f"File count:           {len(results)}")
        print(f"[RAW - V] Overall range: [{min(r['raw_min'] for r in results):.6f}, {max(r['raw_max'] for r in results):.6f}] V")
        print(f"[RAW - V] Avg mean:        {np.mean([r['raw_mean'] for r in results]):.6f} V")
        print(f"[RAW - uV] Overall range: [{min(all_mins):.4f}, {max(all_maxs):.4f}] uV")
        print(f"[RAW - uV] Avg mean:        {np.mean(all_means):.4f} uV")
        print(f"Max value file:       {results[np.argmax(all_maxs)]['filepath']}")
        print(f"Min value file:       {results[np.argmin(all_mins)]['filepath']}")

        # Per-channel mean summary across all files
        n_channels = len(results[0]["channels"])
        ch_names = [results[0]["channels"][i]["name"] for i in range(n_channels)]
        ch_mean_over_files = []
        for ch_idx in range(n_channels):
            ch_means = [results[f_idx]["channels"][ch_idx]["mean"] for f_idx in range(len(results))]
            ch_mean_over_files.append(np.mean(ch_means))

        ch_peak_over_files = []
        for ch_idx in range(n_channels):
            ch_peaks = [results[f_idx]["channels"][ch_idx]["psd_peak_hz"] for f_idx in range(len(results))]
            ch_peak_over_files.append(np.mean(ch_peaks))

        print("\nPer-channel mean across all files:")
        print(f"{'Channel':<15} {'Mean (uV)':<15} {'PSD Peak (Hz)':<15}")
        print("-" * 45)
        for ch_name, ch_mean, ch_peak in zip(ch_names, ch_mean_over_files, ch_peak_over_files):
            print(f"{ch_name:<15} {ch_mean:<15.4f} {ch_peak:<15.2f}")

    return results


def main():
    """Main function with CLI support."""
    import argparse

    # Default analysis directory
    default_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "raw_data")

    parser = argparse.ArgumentParser(
        description="Analyze .bdf files - print amplitude range and mean values",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog=f"""
Examples:
  python bdf_analyzer.py                      # Analyze all .bdf in raw_data/
  python bdf_analyzer.py data/test.bdf       # Analyze single file
  python bdf_analyzer.py data/               # Analyze all .bdf in directory
  python bdf_analyzer.py . -u mV             # Current dir, unit mV
        """
    )
    parser.add_argument(
        "path",
        nargs="?",
        default=default_dir,
        help="Path to BDF file or directory containing BDF files (default: raw_data/)"
    )
    parser.add_argument(
        "-u", "--unit",
        choices=["uV", "mV", "V"],
        default="uV",
        help="Display unit (default: uV)"
    )

    args = parser.parse_args()

    filepath = args.path

    # Determine file or directory mode
    if os.path.isfile(filepath):
        # Single file mode
        result = analyze_bdf(filepath, unit=args.unit)
        if result:
            print("Analysis complete!")
    elif os.path.isdir(filepath):
        # Directory mode
        results = analyze_directory(filepath)
        if results:
            print("\nBatch analysis complete!")
        else:
            print("No analyzable files found")
    else:
        print(f"[ERROR] File does not exist: {filepath}")


if __name__ == "__main__":
    main()
