#!/usr/bin/env python3
"""
高光谱反射率校正工具

功能：
- 读取ENVI ASCII Plot File格式的反射率校正文件
- 读取航带文件夹中的高光谱数据文件 (.bil/.bip/.bsq等ENVI格式)
  注意：spectral库通过读取对应的.hdr头文件来访问数据
- 根据波长匹配进行反射率校正（航带数据 / 校正值）
- 保存校正后的反射率文件

依赖：
- numpy
- GDAL - 用于读取和保存ENVI格式高光谱数据
- pathlib

使用方法：
python redlence.py <航带文件夹路径> <校正文件路径> [输出文件夹路径]

文件要求：
- 航带文件夹中应包含 .bil/.bip/.bsq 文件及其对应的 .hdr 头文件
- 校正文件为ENVI ASCII Plot File格式，包含波长和校正值两列数据
"""

import numpy as np
import os
import sys
from pathlib import Path
from typing import Tuple, List, Dict, Optional
import argparse

# 可选：GDAL库用于读取和保存ENVI格式文件
try:
    from osgeo import gdal
    # GDAL性能优化配置

    GDAL_AVAILABLE = True
except ImportError:
    GDAL_AVAILABLE = False
    print("警告: GDAL不可用，请安装GDAL")


def parse_correction_file(correction_file: str) -> Tuple[np.ndarray, np.ndarray]:
    """
    解析ENVI ASCII Plot File格式的反射率校正文件（优化版本）

    参数:
    -----------
    correction_file : str
        校正文件路径

    返回:
    -----------
    wavelengths : np.ndarray
        波长数组 (nm)
    corrections : np.ndarray
        校正值数组
    """
    try:
        # 使用numpy的loadtxt加速读取（跳过标题行）
        # 首先找到数据开始的行号
        with open(correction_file, 'r', encoding='utf-8') as f:
            lines = f.readlines()

        # 找到数据开始的行索引
        data_start_idx = 0
        for i, line in enumerate(lines):
            line = line.strip()
            if not line or line.startswith(';'):
                continue
            if 'ENVI ASCII Plot File' in line or 'Column 1:' in line or 'Column 2:' in line:
                continue
            # 找到第一个可能是数据行的行
            try:
                parts = line.split()
                if len(parts) >= 2:
                    float(parts[0]), float(parts[1])
                    data_start_idx = i
                    break
            except (ValueError, IndexError):
                continue

        if data_start_idx == 0 and not lines:
            raise ValueError("校正文件中未找到有效的数据行")

        # 使用numpy loadtxt从数据开始行读取
        data = np.loadtxt(correction_file, skiprows=data_start_idx, dtype=float)

        if data.ndim == 1:
            # 如果只有一行数据
            wavelengths = np.array([data[0]])
            corrections = np.array([data[1]])
        else:
            wavelengths = data[:, 0]
            corrections = data[:, 1]

        print(f"✅ 成功解析校正文件: {correction_file}")
        print(f"   数据点数: {len(wavelengths)}")
        print(f"   波长范围: {wavelengths.min():.1f} - {wavelengths.max():.1f} nm")
        print(f"   校正值范围: {corrections.min():.6f} - {corrections.max():.6f}")

        return wavelengths, corrections

    except Exception as e:
        # 如果numpy loadtxt失败，回退到原始方法
        print(f"⚠️  numpy加速读取失败，回退到逐行读取: {e}")
        return parse_correction_file_fallback(correction_file)


def parse_correction_file_fallback(correction_file: str) -> Tuple[np.ndarray, np.ndarray]:
    """
    回退方法：使用原始的逐行解析方式
    """
    wavelengths = []
    corrections = []

    try:
        with open(correction_file, 'r', encoding='utf-8') as f:
            lines = f.readlines()

        # 跳过标题行，找到数据开始
        for line in lines:
            line = line.strip()

            # 跳过空行和注释
            if not line or line.startswith(';'):
                continue

            # 跳过标题
            if 'ENVI ASCII Plot File' in line or 'Column 1:' in line or 'Column 2:' in line:
                continue

            # 尝试解析数据行（波长 校正值）
            try:
                parts = line.split()
                if len(parts) >= 2:
                    wavelength = float(parts[0])
                    correction = float(parts[1])
                    wavelengths.append(wavelength)
                    corrections.append(correction)
            except (ValueError, IndexError):
                # 如果这一行不是数据，可能是其他格式，跳过
                continue

        if not wavelengths:
            raise ValueError("校正文件中未找到有效的数据行")

        wavelengths = np.array(wavelengths, dtype=float)
        corrections = np.array(corrections, dtype=float)

        return wavelengths, corrections

    except Exception as e:
        raise RuntimeError(f"解析校正文件失败: {correction_file}, 错误: {e}")


def find_hyperspectral_files(folder_path: str) -> List[str]:
    """
    查找文件夹中的高光谱数据文件

    支持的格式：.bil, .bip, .bsq等ENVI格式文件
    注意：GDAL可以直接读取ENVI格式文件，会自动查找对应的.hdr头文件

    参数:
    -----------
    folder_path : str
        文件夹路径

    返回:
    -----------
    file_list : List[str]
        高光谱数据文件路径列表 (.bil/.bip/.bsq文件)
    """
    folder = Path(folder_path)
    if not folder.exists():
        raise FileNotFoundError(f"文件夹不存在: {folder_path}")

    # 支持的ENVI格式扩展名
    supported_extensions = ['.bil', '.bip', '.bsq','.dat']

    hyperspectral_files = []
    for ext in supported_extensions:
        files = list(folder.glob(f'*{ext}'))
        hyperspectral_files.extend([str(f) for f in files])

    # 去重（防止同一个文件被多次识别）
    hyperspectral_files = list(set(hyperspectral_files))

    if not hyperspectral_files:
        print(f"警告: 在文件夹 {folder_path} 中未找到高光谱数据文件")
        print("支持的格式: .bil, .bip, .bsq")

    return sorted(hyperspectral_files)


def load_hyperspectral_data(file_path: str) -> Tuple[np.ndarray, Dict]:
    """
    使用GDAL读取高光谱数据文件 - 流式版本

    不加载整个立方体，只返回数据集句柄和元数据

    参数:
    -----------
    file_path : str
        高光谱数据文件路径 (.bil/.bip/.bsq)

    返回:
    -----------
    dataset : gdal.Dataset
        GDAL数据集对象（用于流式读取）
    metadata : dict
        元数据信息
    """
    if not GDAL_AVAILABLE:
        raise RuntimeError("需要GDAL库来读取高光谱文件，请安装GDAL")

    file_path = Path(file_path)

    try:
        # 使用GDAL打开ENVI文件
        dataset = gdal.Open(str(file_path), gdal.GA_ReadOnly)
        if dataset is None:
            raise RuntimeError(f"无法打开文件: {file_path}")

        # 获取基本信息
        lines = dataset.RasterYSize
        samples = dataset.RasterXSize
        bands = dataset.RasterCount

        # 查找对应的HDR文件
        hdr_file = None
        hdr_candidates = [
            file_path.with_suffix('.hdr'),  # datafile.hdr
            file_path.with_suffix(file_path.suffix + '.hdr'),  # datafile.ext.hdr
            file_path.parent / f"{file_path.name}.hdr",  # datafile.ext.hdr (另一种写法)
        ]

        for candidate in hdr_candidates:
            if candidate.exists():
                hdr_file = candidate
                break

        # 尝试从HDR文件中提取波长信息
        wavelengths = None
        if hdr_file and hdr_file.exists():
            try:
                # 读取HDR文件内容
                with open(str(hdr_file), 'r', encoding='utf-8', errors='ignore') as f:
                    hdr_content = f.read()

                # 提取波长信息
                import re
                wavelength_match = re.search(r'wavelength\s*=\s*\{([^}]+)\}', hdr_content, re.IGNORECASE)
                if wavelength_match:
                    wavelength_str = wavelength_match.group(1)
                    # 解析波长值
                    wavelength_values = []
                    for val in wavelength_str.split(','):
                        val = val.strip()
                        try:
                            wavelength_values.append(float(val))
                        except ValueError:
                            continue
                    if wavelength_values:
                        wavelengths = np.array(wavelength_values, dtype=float)

            except Exception as e:
                print(f"⚠️  无法从HDR文件读取波长信息: {e}")

        # 构建元数据
        metadata = {
            'file_path': str(file_path),  # 原始数据文件路径
            'hdr_file': str(hdr_file) if hdr_file else None,  # 对应的hdr文件路径
            'lines': lines,
            'samples': samples,
            'bands': bands,
            'wavelengths': wavelengths,
            'data_type': 'float32',  # 流式读取时的数据类型
            'interleave': 'unknown'  # GDAL不直接提供interleave信息
        }

        print(f"✅ 成功打开高光谱文件: {Path(file_path).name}")
        if hdr_file:
            print(f"   HDR文件: {Path(hdr_file).name}")
        print(f"   数据尺寸: {metadata['lines']} x {metadata['samples']} x {metadata['bands']}")
        print(f"   数据类型: {metadata['data_type']} (流式)")

        if metadata['wavelengths'] is not None:
            print(f"   波长范围: {metadata['wavelengths'][0]:.1f} - {metadata['wavelengths'][-1]:.1f} nm")

        return dataset, metadata

    except Exception as e:
        raise RuntimeError(f"读取高光谱文件失败: {file_path}, 错误: {e}")


def interpolate_corrections(wavelengths_data: np.ndarray, wavelengths_corr: np.ndarray,
                          corrections: np.ndarray) -> np.ndarray:
    """
    将校正值插值到数据波长上

    参数:
    -----------
    wavelengths_data : np.ndarray
        数据文件的波长数组
    wavelengths_corr : np.ndarray
        校正文件的波长数组
    corrections : np.ndarray
        校正值数组

    返回:
    -----------
    interpolated_corrections : np.ndarray
        插值后的校正值数组
    """
    if wavelengths_data is None:
        raise ValueError("数据文件缺少波长信息，无法进行校正")

    try:
        # 使用线性插值
        from scipy.interpolate import interp1d
        interp_func = interp1d(wavelengths_corr, corrections,
                             kind='linear', bounds_error=False,
                             fill_value='extrapolate')
        interpolated = interp_func(wavelengths_data)

        print(f"✅ 成功插值校正值到数据波长")
        print(f"   数据波段数: {len(wavelengths_data)}")
        print(f"   校正数据点数: {len(wavelengths_corr)}")
        print(f"   插值范围: {interpolated.min():.3f} - {interpolated.max():.3f}")

        return interpolated

    except ImportError:
        # 如果没有scipy，使用numpy的interp
        print("警告: scipy不可用，使用numpy进行线性插值")
        interpolated = np.interp(wavelengths_data, wavelengths_corr, corrections)

        print(f"✅ 使用numpy插值校正值到数据波长")
        print(f"   插值范围: {interpolated.min():.3f} - {interpolated.max():.3f}")

        return interpolated


def apply_reflectance_correction_streaming(input_dataset, output_dataset, corrections: np.ndarray, block_size: int = 1024):
    """
    应用反射率校正 - 流式版本

    按块读取→校正→写入，避免加载整个立方体

    参数:
    -----------
    input_dataset : gdal.Dataset
        输入数据集
    output_dataset : gdal.Dataset
        输出数据集
    corrections : np.ndarray
        校正值数组 (bands,)
    block_size : int
        块大小（行数）
    """
    lines = input_dataset.RasterYSize
    samples = input_dataset.RasterXSize
    bands = input_dataset.RasterCount

    if bands != len(corrections):
        raise ValueError(f"数据波段数 ({bands}) 与校正值数量 ({len(corrections)}) 不匹配")

    print("🔢 正在应用反射率校正（流式处理，向量化加速）...")

    # 用“乘倒数”替代逐元素除法，并在无效校正值(0/NaN/Inf)处直接置零
    corrections = np.asarray(corrections, dtype=np.float32)
    scale = np.zeros((bands,), dtype=np.float32)
    valid = np.isfinite(corrections) & (corrections != 0)
    scale[valid] = np.float32(10000.0) / corrections[valid]
    scale_3d = scale[:, None, None]

    # 提前缓存输出波段对象，避免循环内重复 GetRasterBand
    output_bands = [output_dataset.GetRasterBand(i + 1) for i in range(bands)]

    total_blocks = (lines + block_size - 1) // block_size

    # 按块处理：每个块一次性读全波段并向量化计算
    for block_idx, y_start in enumerate(range(0, lines, block_size), start=1):
        y_end = min(y_start + block_size, lines)
        actual_block_size = y_end - y_start

        # 低频打印进度，避免大量I/O拖慢处理
        if block_idx == 1 or block_idx == total_blocks or block_idx % 10 == 0:
            print(f"   处理块 {block_idx}/{total_blocks}: 行 {y_start}-{y_end-1} ({actual_block_size} 行)")

        block = input_dataset.ReadAsArray(0, y_start, samples, actual_block_size)
        if block is None:
            raise RuntimeError(f"读取数据块失败: y_start={y_start}, block_size={actual_block_size}")

        # 统一维度为 (bands, block_y, samples)
        if block.ndim == 2:
            block = block[np.newaxis, :, :]

        block_f = block.astype(np.float32, copy=False)
        np.multiply(block_f, scale_3d, out=block_f, casting='unsafe')
        np.clip(block_f, 0, 65535, out=block_f)
        block_u16 = block_f.astype(np.uint16, copy=False)

        # GDAL按波段写出
        for band_idx in range(bands):
            output_bands[band_idx].WriteArray(block_u16[band_idx, :, :], 0, y_start)

    print("✅ 成功应用反射率校正（流式处理，向量化加速）")


def save_corrected_data_streaming(input_dataset, corrections: np.ndarray, output_file: str,
                             wavelengths: Optional[np.ndarray] = None, source_hdr: Optional[str] = None):
    """
    保存校正后的反射率数据为ENVI格式 - 流式版本

    参数:
    -----------
    input_dataset : gdal.Dataset
        输入数据集
    corrections : np.ndarray
        校正值数组
    output_file : str
        输出文件路径（不含扩展名）
    wavelengths : np.ndarray, optional
        波长信息
    source_hdr : str, optional
        源HDR文件路径，用于复制HDR内容
    """
    lines = input_dataset.RasterYSize
    samples = input_dataset.RasterXSize
    bands = input_dataset.RasterCount

    # 确保输出目录存在
    output_path = Path(output_file)
    output_path.parent.mkdir(parents=True, exist_ok=True)

    # 输出文件路径
    bil_file = str(output_path.with_suffix('.dat'))
    hdr_file = str(output_path.with_suffix('.hdr'))

    try:
        # 创建输出数据集
        driver = gdal.GetDriverByName('ENVI')
        output_dataset = driver.Create(bil_file, samples, lines, bands, gdal.GDT_UInt16,
                                     options=['INTERLEAVE=BSQ'])

        if output_dataset is None:
            raise RuntimeError(f"无法创建ENVI数据集: {bil_file}")

        # 设置NoData值
        for band_idx in range(bands):
            output_band = output_dataset.GetRasterBand(band_idx + 1)
            output_band.SetNoDataValue(0)

        # 应用流式校正和保存
        apply_reflectance_correction_streaming(input_dataset, output_dataset, corrections)

        # 关闭输出数据集
        output_dataset = None

        # 处理HDR文件
        if source_hdr and Path(source_hdr).exists():
            import shutil
            shutil.copy2(source_hdr, hdr_file)
            print(f"✅ 已复制源HDR文件: {Path(source_hdr).name}")
        else:
            # 创建HDR头文件
            create_envi_header(hdr_file, lines, samples, bands, wavelengths, None)

        print(f"✅ 成功保存校正结果:")
        print(f"   数据文件: {bil_file}")
        print(f"   头文件: {hdr_file}")
        print(f"   数据尺寸: {lines} x {samples} x {bands}")
        print(f"   数据类型: uint16 (反射率x10000)")
        print(f"   处理方式: 流式处理")

    except Exception as e:
        raise RuntimeError(f"保存文件失败: {output_file}, 错误: {e}")


def save_with_gdal(data: np.ndarray, bil_file: str, wavelengths: Optional[np.ndarray] = None,
                   source_file: Optional[str] = None, source_hdr: Optional[str] = None):
    """
    使用GDAL保存ENVI格式文件
    """
    lines, samples, bands = data.shape
    hdr_file = bil_file.replace('.dat', '.hdr')

    # 创建GDAL驱动
    driver = gdal.GetDriverByName('ENVI')

    # 创建数据集 - 使用uint16格式优化性能和文件大小
    dataset = driver.Create(bil_file, samples, lines, bands, gdal.GDT_UInt16,
                           options=['INTERLEAVE=BSQ'])

    if dataset is None:
        raise RuntimeError(f"无法创建ENVI数据集: {bil_file}")

    try:
        # 设置元数据
        metadata = dataset.GetMetadata()
        metadata['DESCRIPTION'] = 'Reflectance corrected hyperspectral data using Python'
        metadata['SENSOR_TYPE'] = 'Hyperspectral'
        metadata['DATA_UNITS'] = 'Reflectance'
        metadata['PROCESSING_ALGORITHM'] = 'Reflectance Correction'
        metadata['CREATION_DATE'] = str(np.datetime64('now'))

        if source_file:
            metadata['SOURCE_FILE'] = Path(source_file).name

        # 添加波长信息到元数据
        if wavelengths is not None and len(wavelengths) == bands:
            metadata['wavelength_units'] = 'nm'
            for i, wl in enumerate(wavelengths):
                metadata[f'wavelength_{i+1}'] = str(wl)

        dataset.SetMetadata(metadata)

        # 写入数据 - 优化版本：转换为uint16格式
        print(f"💾 正在写入 {bands} 个波段的数据...")

        # 将反射率转换为uint16（乘以10000以保留4位小数精度，裁剪到有效范围）
        data_uint16 = np.clip(data * 10000, 0, 65535).astype(np.uint16, copy=False)

        for band_idx in range(bands):
            band = dataset.GetRasterBand(band_idx + 1)
            band_data = data_uint16[:, :, band_idx]
            band.WriteArray(band_data)
            band.SetNoDataValue(0)  # uint16的NoData值为0

            # 简化：只在必要时设置波段描述（可选优化：完全移除以提升速度）
            # if wavelengths is not None and band_idx < len(wavelengths):
            #     band.SetDescription(f'{wavelengths[band_idx]:.1f} nm')

            # 每处理100个波段显示一次进度（减少打印频率）
            if bands >= 100 and (band_idx + 1) % 100 == 0:
                print(f"   已写入 {band_idx + 1}/{bands} 个波段")

        print(f"✅ 数据写入完成 ({bands} 个波段)")

        # 创建HDR头文件（GDAL会自动创建基本的HDR，但我们需要添加更多信息）
        create_envi_header(hdr_file, lines, samples, bands, wavelengths, source_file)

    finally:
        # 关闭数据集
        dataset = None


def save_with_numpy(data: np.ndarray, bil_file: str, hdr_file: str,
                   wavelengths: Optional[np.ndarray] = None, source_file: Optional[str] = None, source_hdr: Optional[str] = None):
    """
    使用numpy保存ENVI格式文件（GDAL不可用时的回退方案，优化版本）
    """
    lines, samples, bands = data.shape

    print(f"💾 正在保存 {bands} 个波段的数据...")

    # 保存二进制数据 - uint16格式：预先转换数据类型
    with open(bil_file, 'wb') as f:
        # 将反射率转换为uint16（乘以10000以保留4位小数精度，裁剪到有效范围）
        data_to_save = np.clip(data * 10000, 0, 65535).astype(np.uint16, copy=False)
        data_to_save.tofile(f)

    print(f"✅ 数据文件写入完成")

    # 如果有源HDR文件，直接复制
    if source_hdr and Path(source_hdr).exists():
        import shutil
        shutil.copy2(source_hdr, hdr_file)
        print(f"✅ 已复制源HDR文件: {Path(source_hdr).name}")
    else:
        # 创建HDR头文件
        create_envi_header(hdr_file, lines, samples, bands, wavelengths, source_file)


def create_envi_header(hdr_file: str, lines: int, samples: int, bands: int,
                      wavelengths: Optional[np.ndarray] = None, source_file: Optional[str] = None):
    """
    创建ENVI格式的HDR头文件
    """
    with open(hdr_file, 'w', encoding='utf-8') as f:
        f.write("ENVI\n")
        f.write("description = {\n")
        f.write("  Reflectance corrected hyperspectral data\n")
        f.write("  Processed with Python reflectance correction}\n")
        f.write(f"samples = {samples}\n")
        f.write(f"lines = {lines}\n")
        f.write(f"bands = {bands}\n")
        f.write("header offset = 0\n")
        f.write("file type = ENVI Standard\n")
        f.write("data type = 12\n")  # uint16
        f.write("interleave = bsq\n")
        f.write("sensor type = Hyperspectral\n")
        f.write("byte order = 0\n")  # little-endian
        f.write("reflectance scale factor = 10000\n")  # 反射率缩放因子

        # 添加波长信息
        if wavelengths is not None and len(wavelengths) == bands:
            f.write("wavelength units = nm\n")
            f.write("wavelength = {\n")
            for i, wl in enumerate(wavelengths):
                f.write(f"  {wl}")
                if i < len(wavelengths) - 1:
                    f.write(",")
                if (i + 1) % 10 == 0:  # 每10个波长换行
                    f.write("\n")
            f.write("}\n")

            # 添加波段名称
            f.write("band names = {\n")
            for i, wl in enumerate(wavelengths):
                f.write(f"  {wl:.1f} nm")
                if i < len(wavelengths) - 1:
                    f.write(",")
                if (i + 1) % 8 == 0:  # 每8个波段名称换行
                    f.write("\n")
            f.write("}\n")




def process_single_file(hyp_file: str, wavelengths_corr: np.ndarray, corrections: np.ndarray,
                       output_dir: str) -> bool:
    """
    处理单个高光谱文件

    参数:
    -----------
    hyp_file : str
        高光谱文件路径
    wavelengths_corr : np.ndarray
        校正文件的波长
    corrections : np.ndarray
        校正值
    output_dir : str
        输出目录

    返回:
    -----------
    success : bool
        处理是否成功
    """
    try:
        print(f"\n🔄 处理文件: {Path(hyp_file).name}")

        # 读取高光谱数据（流式）
        input_dataset, metadata = load_hyperspectral_data(hyp_file)

        try:
            # 获取数据波长
            wavelengths_data = metadata.get('wavelengths')
            if wavelengths_data is None:
                print(f"⚠️  跳过文件 {Path(hyp_file).name}: 缺少波长信息")
                return False

            # 判断数据波长和校正波长是否一致
            wavelengths_data = np.array(wavelengths_data)
            if len(wavelengths_data) == len(wavelengths_corr) and np.allclose(wavelengths_data, wavelengths_corr, rtol=1e-6):
                # 波长完全一致，直接使用校正值
                print("✅ 数据波长与校正波长完全一致，无需插值")
                interpolated_corrections = corrections
            else:
                # 波长不一致，需要插值
                print("🔄 数据波长与校正波长不一致，进行插值")
                interpolated_corrections = interpolate_corrections(
                    wavelengths_data, wavelengths_corr, corrections
                )

            # 生成输出文件名
            input_name = Path(hyp_file).stem
            output_file = Path(output_dir) / f"{input_name}_reflectance"

            # 流式保存结果（包含校正）
            save_corrected_data_streaming(input_dataset, interpolated_corrections, str(output_file),
                                        wavelengths_data, metadata.get('hdr_file'))

        finally:
            # 确保关闭输入数据集
            input_dataset = None

        print(f"✅ 成功处理文件: {Path(hyp_file).name}")
        return True

    except Exception as e:
        print(f"❌ 处理文件失败: {Path(hyp_file).name}, 错误: {e}")
        return False


def batch_process(hyperspectral_dir: str, correction_file: str, output_dir: str) -> Dict[str, int]:
    """
    批量处理文件夹中的所有高光谱文件

    参数:
    -----------
    hyperspectral_dir : str
        高光谱文件文件夹
    correction_file : str
        校正文件路径
    output_dir : str
        输出目录

    返回:
    -----------
    results : dict
        处理结果统计
    """
    print("=" * 60)
    print("🏁 开始高光谱反射率校正批量处理")
    print("=" * 60)

    # 检查依赖
    if not GDAL_AVAILABLE:
        print("❌ 错误: 需要安装GDAL库")
        return {'total': 0, 'success': 0, 'failed': 0}

    # 确保输出目录存在
    Path(output_dir).mkdir(parents=True, exist_ok=True)

    try:
        # 解析校正文件
        print("📖 解析校正文件...")
        wavelengths_corr, corrections = parse_correction_file(correction_file)

        # 查找高光谱文件
        print(f"\n📂 查找高光谱文件...")
        hyp_files = find_hyperspectral_files(hyperspectral_dir)

        if not hyp_files:
            print("❌ 未找到高光谱文件，处理终止")
            return {'total': 0, 'success': 0, 'failed': 0}

        print(f"找到 {len(hyp_files)} 个高光谱数据文件:")
        for f in hyp_files:
            print(f"  - {Path(f).name} (需要对应的.hdr头文件)")

        # 处理每个文件
        results = {'total': len(hyp_files), 'success': 0, 'failed': 0}

        for hyp_file in hyp_files:
            success = process_single_file(hyp_file, wavelengths_corr, corrections, output_dir)
            if success:
                results['success'] += 1
            else:
                results['failed'] += 1

        # 输出总结
        print("\n" + "=" * 60)
        print("📊 处理完成总结:")
        print(f"   总文件数: {results['total']}")
        print(f"   成功处理: {results['success']}")
        print(f"   处理失败: {results['failed']}")
        print(f"   输出目录: {output_dir}")
        print("=" * 60)

        return results

    except Exception as e:
        print(f"❌ 批量处理失败: {e}")
        return {'total': 0, 'success': 0, 'failed': 0}


def main():
    """
    主函数 - 命令行接口
    """
    parser = argparse.ArgumentParser(
        description='高光谱反射率校正工具',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
文件要求:
- 航带文件夹中应包含ENVI格式的高光谱数据文件(.bil/.bip/.bsq)和对应的头文件(.hdr)
- 校正文件应为ENVI ASCII Plot File格式，包含波长和校正值两列数据

使用示例:
  python redlence.py /path/to/hyperspectral/folder /path/to/correction.txt
  python redlence.py /path/to/hyperspectral/folder /path/to/correction.txt /path/to/output/folder
        """
    )

    parser.add_argument('hyperspectral_dir', help='包含高光谱文件的文件夹路径')
    parser.add_argument('correction_file', help='反射率校正文件路径 (ENVI ASCII Plot File格式)')
    parser.add_argument('output_dir', nargs='?', default=None,
                       help='输出目录路径 (可选，默认在输入文件夹下创建output文件夹)')

    args = parser.parse_args()

    # 设置默认输出目录
    if args.output_dir is None:
        args.output_dir = str(Path(args.hyperspectral_dir) / 'reflectance_output')

    # 检查输入文件存在
    if not Path(args.correction_file).exists():
        print(f"❌ 校正文件不存在: {args.correction_file}")
        return 1

    if not Path(args.hyperspectral_dir).exists():
        print(f"❌ 高光谱文件夹不存在: {args.hyperspectral_dir}")
        return 1

    # 执行批量处理
    results = batch_process(args.hyperspectral_dir, args.correction_file, args.output_dir)

    # 返回适当的退出码
    if results['success'] > 0:
        print("✅ 处理完成！")
        return 0
    else:
        print("❌ 没有成功处理任何文件")
        return 1


if __name__ == "__main__":
    exit(main())