import React, { useEffect, useRef, useState } from 'react';
import './App.css';
import { useI18n } from './i18n/I18nContext';
import { getAssetInventoryStatus, scanAssetInventory, unpackSentinel1Batch } from './api/assets';

const DEFAULT_MONITOR_CONFIG = {
  radar_dirs: [],
  orbit_dir: '',
  dinsar_dirs: [],
  gf3_archive_source_dirs: [],
  gf3_source_dirs: [],
  gf3_sarscape_native_dirs: [],
  gf3_storage_dirs: [],
  gf3_sarscape_wrapper_exe: '',
  gf3_sarscape_idlrt_path: '',
  gf3_sarscape_dem_path: '',
  gf3_sarscape_polarizations: 'HH,HV',
  gf3_sarscape_auto_standardize: true,
  gf3_sarscape_clean_after_success: true,
  s1_source_dirs: [],
  s1_storage_dirs: [],
  s1_orbit_dirs: [],
};

const DEFAULT_UNPACK_CONFIG = {
  source_dirs: [],
  insar_storage_dirs: [],
  min_disk_space_gb: 50,
  max_files_per_run: 0,
  max_runtime_minutes: 0,
  delete_archive: true,
  tmp_suffix: '.unpack_tmp',
  archive_exts: [],
};

const toArray = (value) => (Array.isArray(value) ? value : []);

const createUnpackRunOptions = (config = DEFAULT_UNPACK_CONFIG) => ({
  max_files_per_run: String(config?.max_files_per_run ?? 0),
  max_runtime_minutes: String(config?.max_runtime_minutes ?? 0),
});

const parseUnpackRunValue = (rawValue, label) => {
  const value = String(rawValue ?? '').trim();
  if (!value) {
    return 0;
  }

  const parsed = Number(value);
  if (!Number.isInteger(parsed) || parsed < 0) {
    throw new Error(`${label}必须是大于等于 0 的整数`);
  }
  return parsed;
};

const formatList = (list) => (Array.isArray(list) && list.length ? list.join('; ') : '未配置');
const normalizeComparePath = (value) => String(value || '').trim().replace(/\\/g, '/').replace(/\/+$/, '').toLowerCase();

const DataMonitorPanel = ({ apiEndpoint, onTaskStart, readOnly = false, enabled = true }) => {
  const { t } = useI18n();
  const [config, setConfig] = useState(DEFAULT_MONITOR_CONFIG);
  const [configLoaded, setConfigLoaded] = useState(false);
  const [logs, setLogs] = useState([]);
  const [activeTasks, setActiveTasks] = useState([]);
  const [unpackConfig, setUnpackConfig] = useState(DEFAULT_UNPACK_CONFIG);
  const [unpackLoading, setUnpackLoading] = useState(false);
  const [unpackMessage, setUnpackMessage] = useState('');
  const [showUnpackDialog, setShowUnpackDialog] = useState(false);
  const [unpackRunOptions, setUnpackRunOptions] = useState(() => createUnpackRunOptions());
  const [unpackDialogError, setUnpackDialogError] = useState('');
  const [unpackTaskId, setUnpackTaskId] = useState('');
  const [unpackTaskTerminal, setUnpackTaskTerminal] = useState(false);
  const [s1Loading, setS1Loading] = useState(false);
  const [s1ScanLoading, setS1ScanLoading] = useState(false);
  const [s1Message, setS1Message] = useState('');
  const [gf3UnpackLoading, setGf3UnpackLoading] = useState(false);
  const [gf3ProcessLoading, setGf3ProcessLoading] = useState(false);
  const [gf3SarscapeProduceLoading, setGf3SarscapeProduceLoading] = useState(false);
  const [gf3SarscapeSyncLoading, setGf3SarscapeSyncLoading] = useState(false);
  const [gf3SarscapeCleanLoading, setGf3SarscapeCleanLoading] = useState(false);
  const [gf3ScanLoading, setGf3ScanLoading] = useState(false);
  const [gf3Message, setGf3Message] = useState('');
  const logEndRef = useRef(null);

  const parseJsonSafe = async (response, fallback) => {
    try {
      return await response.json();
    } catch {
      return fallback;
    }
  };

  const displayLogs = toArray(logs);
  const displayActiveTasks = toArray(activeTasks);
  const unpackActiveTask = displayActiveTasks.find((task) =>
    task.task_id === unpackTaskId || task.task_type === 'UNPACK_ARCHIVES'
  );
  const s1ActiveTask = displayActiveTasks.find((task) => task.task_type === 'UNPACK_SENTINEL1');
  const gf3ActiveTask = displayActiveTasks.find((task) =>
    ['GF3_UNPACK', 'GF3_BATCH_PROCESS', 'GF3_SARSCAPE_PRODUCE', 'GF3_SARSCAPE_SYNC', 'GF3_SARSCAPE_CLEAN'].includes(task.task_type)
  );

  useEffect(() => {
    if (!enabled) {
      setConfig(DEFAULT_MONITOR_CONFIG);
      setConfigLoaded(false);
      return;
    }

    let canceled = false;
    fetch(`${apiEndpoint}/monitor/status`, { credentials: 'include' })
      .then(async (res) => {
        const data = await parseJsonSafe(res, {});
        if (!res.ok) {
          throw new Error(data?.detail || `HTTP ${res.status}`);
        }
        return data;
      })
      .then((data) => {
        if (canceled) {
          return;
        }
        setConfig({
          ...DEFAULT_MONITOR_CONFIG,
          ...data,
          radar_dirs: toArray(data?.radar_dirs),
          dinsar_dirs: toArray(data?.dinsar_dirs),
          s1_source_dirs: toArray(data?.s1_source_dirs),
          s1_storage_dirs: toArray(data?.s1_storage_dirs),
          s1_orbit_dirs: toArray(data?.s1_orbit_dirs),
          gf3_archive_source_dirs: toArray(data?.gf3_archive_source_dirs),
          gf3_source_dirs: toArray(data?.gf3_source_dirs),
          gf3_sarscape_native_dirs: toArray(data?.gf3_sarscape_native_dirs),
          gf3_storage_dirs: toArray(data?.gf3_storage_dirs),
        });
        setConfigLoaded(true);
      })
      .catch((err) => {
        if (canceled) {
          return;
        }
        console.error('Failed to fetch monitor status:', err);
        setConfigLoaded(false);
      });

    return () => {
      canceled = true;
    };
  }, [apiEndpoint, enabled]);

  useEffect(() => {
    if (!enabled) {
      setUnpackConfig(DEFAULT_UNPACK_CONFIG);
      setShowUnpackDialog(false);
      setUnpackRunOptions(createUnpackRunOptions());
      setUnpackDialogError('');
      return;
    }

    let canceled = false;
    fetch(`${apiEndpoint}/unpack/config`, { credentials: 'include' })
      .then(async (res) => {
        const data = await parseJsonSafe(res, {});
        if (!res.ok) {
          throw new Error(data?.detail || `HTTP ${res.status}`);
        }
        return data;
      })
      .then((data) => {
        if (canceled) {
          return;
        }
        setUnpackConfig({
          ...DEFAULT_UNPACK_CONFIG,
          ...data,
          source_dirs: toArray(data?.source_dirs),
          insar_storage_dirs: toArray(data?.insar_storage_dirs),
        });
      })
      .catch((err) => {
        if (canceled) {
          return;
        }
        console.error('Failed to fetch unpack config:', err);
      });

    return () => {
      canceled = true;
    };
  }, [apiEndpoint, enabled]);

  useEffect(() => {
    if (!enabled) {
      setLogs([]);
      setActiveTasks([]);
      setUnpackTaskId('');
      setUnpackTaskTerminal(false);
      return;
    }

    let canceled = false;
    const fetchLogsAndTasks = async () => {
      try {
        const [logsRes, tasksRes] = await Promise.all([
          fetch(`${apiEndpoint}/monitor/logs`, { credentials: 'include' }),
          fetch(`${apiEndpoint}/tasks/active`, { credentials: 'include' }),
        ]);
        const [logsData, tasksData] = await Promise.all([
          parseJsonSafe(logsRes, {}),
          parseJsonSafe(tasksRes, []),
        ]);

        if (canceled) {
          return;
        }
        setLogs(logsRes.ok ? toArray(logsData?.logs) : []);
        setActiveTasks(tasksRes.ok ? toArray(tasksData) : []);
      } catch (err) {
        if (canceled) {
          return;
        }
        console.error('Failed to fetch logs or tasks:', err);
      }
    };

    fetchLogsAndTasks();
    const intervalId = setInterval(fetchLogsAndTasks, 2000);

    return () => {
      canceled = true;
      clearInterval(intervalId);
    };
  }, [apiEndpoint, enabled]);

  useEffect(() => {
    if (!enabled) {
      setUnpackTaskId('');
      setUnpackTaskTerminal(false);
      return;
    }

    if (unpackActiveTask) {
      if (!unpackTaskId) {
        setUnpackTaskId(unpackActiveTask.task_id);
      }
      setUnpackTaskTerminal(false);
      setUnpackMessage(
        `运行中 (${unpackActiveTask.progress || 0}%): ${unpackActiveTask.message || '正在解包 LT-1 归档...'}`
      );
      return;
    }

    if (!unpackTaskId || unpackTaskTerminal) {
      return;
    }

    let canceled = false;
    fetch(`${apiEndpoint}/tasks/${unpackTaskId}`, { credentials: 'include' })
      .then(async (res) => {
        const data = await parseJsonSafe(res, null);
        if (!res.ok) {
          throw new Error(data?.detail || `HTTP ${res.status}`);
        }
        return data;
      })
      .then((task) => {
        if (canceled || !task) {
          return;
        }
        if (task.status === 'COMPLETED') {
          setUnpackMessage(task.message || 'LT-1 解包已完成。');
          setUnpackTaskTerminal(true);
        } else if (task.status === 'FAILED') {
          setUnpackMessage(`失败：${task.message || 'LT-1 解包任务失败'}`);
          setUnpackTaskTerminal(true);
        }
      })
      .catch((err) => {
        if (canceled) {
          return;
        }
        console.error('Failed to fetch unpack task status:', err);
      });

    return () => {
      canceled = true;
    };
  }, [apiEndpoint, enabled, unpackActiveTask, unpackTaskId, unpackTaskTerminal]);

  useEffect(() => {
    if (logEndRef.current) {
      logEndRef.current.scrollIntoView({ behavior: 'smooth' });
    }
  }, [logs]);

  const hasRadarDirs = config.radar_dirs.length > 0;
  const hasOrbitDir = typeof config.orbit_dir === 'string' && config.orbit_dir.trim() !== '';
  const hasS1SourceDirs = config.s1_source_dirs.length > 0;
  const hasS1StorageDirs = config.s1_storage_dirs.length > 0;
  const hasS1OrbitDirs = config.s1_orbit_dirs.length > 0;
  const hasGf3ArchiveSourceDirs = config.gf3_archive_source_dirs.length > 0;
  const hasGf3SourceDirs = config.gf3_source_dirs.length > 0;
  const hasGf3SarscapeNativeDirs = config.gf3_sarscape_native_dirs.length > 0;
  const hasGf3StorageDirs = config.gf3_storage_dirs.length > 0;
  const hasGf3SarscapeWrapper = typeof config.gf3_sarscape_wrapper_exe === 'string' && config.gf3_sarscape_wrapper_exe.trim() !== '';
  const hasGf3SarscapeDem = typeof config.gf3_sarscape_dem_path === 'string' && config.gf3_sarscape_dem_path.trim() !== '';

  const canRunRadar = !readOnly && configLoaded && hasRadarDirs;
  const canRunOrbit = !readOnly && configLoaded && hasOrbitDir;
  const canRunS1 = !readOnly && configLoaded && (hasS1SourceDirs || hasS1StorageDirs || hasS1OrbitDirs);
  const canRunS1Scan = !readOnly && configLoaded && hasS1SourceDirs;
  const canRunS1OrbitScan = !readOnly && configLoaded && hasS1OrbitDirs;
  const canRunGf3Scan = !readOnly && configLoaded && hasGf3StorageDirs;
  const canRunGf3Unpack = !readOnly && configLoaded && hasGf3ArchiveSourceDirs && hasGf3SourceDirs;
  const canRunGf3Process = !readOnly && configLoaded && hasGf3SourceDirs;
  const canRunGf3SarscapeProduce = !readOnly && configLoaded && hasGf3ArchiveSourceDirs && hasGf3SarscapeNativeDirs && hasGf3StorageDirs && hasGf3SarscapeWrapper && hasGf3SarscapeDem;
  const canRunGf3SarscapeSync = !readOnly && configLoaded && hasGf3SarscapeNativeDirs && hasGf3StorageDirs;
  const canRunGf3SarscapeClean = !readOnly && configLoaded && hasGf3SarscapeNativeDirs && hasGf3StorageDirs;
  const canOpenUnpackDialog = !readOnly && unpackConfig.source_dirs.length > 0;

  const handleS1Run = async () => {
    if (readOnly) {
      setS1Message('当前账户为只读模式，无法触发 Sentinel-1 任务。');
      return;
    }
    setS1Loading(true);
    setS1Message('Sentinel-1 任务启动中...');
    try {
      const res = await unpackSentinel1Batch({
        scan_before_unpack: true,
        overwrite: false,
      });
      setS1Message(res.message || 'Sentinel-1 任务已启动');
      if (onTaskStart) {
        onTaskStart(res.task_id, 'Sentinel-1 任务已启动。', {
          nonBlocking: true,
          taskType: 'UNPACK_SENTINEL1',
        });
      }
    } catch (err) {
      setS1Message(`失败：${err?.response?.data?.detail || err.message || '未知错误'}`);
    } finally {
      setS1Loading(false);
    }
  };

  const handleS1Scan = async () => {
    if (readOnly) {
      setS1Message('当前账户为只读模式，无法触发 Sentinel-1 扫描。');
      return;
    }
    setS1ScanLoading(true);
    setS1Message('Sentinel-1 源数据扫描启动中...');
    try {
      const inventoryStatus = await getAssetInventoryStatus();
      const sourcePathSet = new Set(config.s1_source_dirs.map(normalizeComparePath));
      const rootIds = (inventoryStatus?.states || [])
        .filter((item) => item?.inventory_type === 'source_product' && sourcePathSet.has(normalizeComparePath(item?.root_path)))
        .map((item) => item.root_ref_id)
        .filter((value, index, array) => value && array.indexOf(value) === index);
      const res = await scanAssetInventory({
        inventory_types: ['source_product'],
        root_ids: rootIds,
        bind_orbits: true,
      });
      setS1Message(res.message || 'Sentinel-1 源数据扫描任务已启动');
      onTaskStart?.(res.task_id, 'Sentinel-1 源数据扫描任务已启动。', {
        nonBlocking: true,
        taskType: 'SCAN_ASSET_INVENTORY',
      });
    } catch (err) {
      setS1Message(`失败：${err?.response?.data?.detail || err.message || '未知错误'}`);
    } finally {
      setS1ScanLoading(false);
    }
  };

  const handleS1OrbitScan = async () => {
    if (readOnly) {
      setS1Message('当前账户为只读模式，无法触发 Sentinel-1 精轨扫描。');
      return;
    }
    setS1ScanLoading(true);
    setS1Message('Sentinel-1 精轨扫描启动中...');
    try {
      const inventoryStatus = await getAssetInventoryStatus();
      const orbitPathSet = new Set(config.s1_orbit_dirs.map(normalizeComparePath));
      const rootIds = (inventoryStatus?.states || [])
        .filter((item) => item?.inventory_type === 'orbit_asset' && orbitPathSet.has(normalizeComparePath(item?.root_path)))
        .map((item) => item.root_ref_id)
        .filter((value, index, array) => value && array.indexOf(value) === index);
      const res = await scanAssetInventory({
        inventory_types: ['orbit_asset'],
        root_ids: rootIds,
        bind_orbits: true,
      });
      setS1Message(res.message || 'Sentinel-1 精轨扫描任务已启动');
      onTaskStart?.(res.task_id, 'Sentinel-1 精轨扫描任务已启动。', {
        nonBlocking: true,
        taskType: 'SCAN_ASSET_INVENTORY',
      });
    } catch (err) {
      setS1Message(`失败：${err?.response?.data?.detail || err.message || '未知错误'}`);
    } finally {
      setS1ScanLoading(false);
    }
  };

  const handleGf3BatchProcess = async () => {
    if (readOnly) {
      setGf3Message('当前账户为只读模式，无法触发 GF3 预处理。');
      return;
    }
    setGf3ProcessLoading(true);
    setGf3Message('GF3 预处理启动中...');
    try {
      const res = await fetch(`${apiEndpoint}/monitor/gf3-process`, {
        method: 'POST',
        credentials: 'include',
      });
      const data = await parseJsonSafe(res, {});
      if (res.ok) {
        setGf3Message(data.message || 'GF3 批量处理任务已启动');
        if (onTaskStart) {
          onTaskStart(data.task_id, 'GF3 L1A→L2 批量处理已启动。');
        }
      } else {
        setGf3Message(`失败：${data.detail || '未知错误'}`);
      }
    } catch (err) {
      setGf3Message(`失败：${err.message || '未知错误'}`);
    } finally {
      setGf3ProcessLoading(false);
    }
  };

  const handleGf3Unpack = async () => {
    if (readOnly) {
      setGf3Message('当前账户为只读模式，无法触发 GF3 解包。');
      return;
    }
    setGf3UnpackLoading(true);
    setGf3Message('GF3 解包启动中...');
    try {
      const res = await fetch(`${apiEndpoint}/monitor/gf3-unpack`, {
        method: 'POST',
        credentials: 'include',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({}),
      });
      const data = await parseJsonSafe(res, {});
      if (res.ok) {
        setGf3Message(data.message || 'GF3 解包任务已启动');
        if (onTaskStart) {
          onTaskStart(data.task_id, 'GF3 解包任务已启动。', {
            nonBlocking: true,
            taskType: 'GF3_UNPACK',
          });
        }
      } else {
        setGf3Message(`失败：${data.detail || '未知错误'}`);
      }
    } catch (err) {
      setGf3Message(`失败：${err.message || '未知错误'}`);
    } finally {
      setGf3UnpackLoading(false);
    }
  };

  const handleGf3SarscapeProduce = async () => {
    if (readOnly) {
      setGf3Message('当前账户为只读模式，无法触发 GF3 SARscape 生产。');
      return;
    }
    setGf3SarscapeProduceLoading(true);
    setGf3Message('GF3 SARscape 生产链路启动中...');
    try {
      const res = await fetch(`${apiEndpoint}/monitor/gf3-sarscape-produce`, {
        method: 'POST',
        credentials: 'include',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({}),
      });
      const data = await parseJsonSafe(res, {});
      if (res.ok) {
        setGf3Message(data.message || 'GF3 SARscape 生产任务已启动');
        if (onTaskStart) {
          onTaskStart(data.task_id, 'GF3 SARscape 生产链路已启动。', {
            nonBlocking: true,
            taskType: 'GF3_SARSCAPE_PRODUCE',
          });
        }
      } else {
        setGf3Message(`失败：${data.detail || '未知错误'}`);
      }
    } catch (err) {
      setGf3Message(`失败：${err.message || '未知错误'}`);
    } finally {
      setGf3SarscapeProduceLoading(false);
    }
  };

  const handleGf3SarscapeSync = async () => {
    if (readOnly) {
      setGf3Message('当前账户为只读模式，无法触发 GF3 SARscape 标准化。');
      return;
    }
    setGf3SarscapeSyncLoading(true);
    setGf3Message('GF3 SARscape 原生结果标准化启动中...');
    try {
      const res = await fetch(`${apiEndpoint}/monitor/gf3-sarscape-sync`, {
        method: 'POST',
        credentials: 'include',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({}),
      });
      const data = await parseJsonSafe(res, {});
      if (res.ok) {
        setGf3Message(data.message || 'GF3 SARscape 标准化任务已启动');
        if (onTaskStart) {
          onTaskStart(data.task_id, 'GF3 SARscape 原生结果标准化已启动。', {
            nonBlocking: true,
            taskType: 'GF3_SARSCAPE_SYNC',
          });
        }
      } else {
        setGf3Message(`失败：${data.detail || '未知错误'}`);
      }
    } catch (err) {
      setGf3Message(`失败：${err.message || '未知错误'}`);
    } finally {
      setGf3SarscapeSyncLoading(false);
    }
  };

  const handleGf3SarscapeClean = async () => {
    if (readOnly) {
      setGf3Message('当前账户为只读模式，无法触发 GF3 SARscape 清理。');
      return;
    }
    setGf3SarscapeCleanLoading(true);
    setGf3Message('GF3 SARscape 中间数据清理启动中...');
    try {
      const res = await fetch(`${apiEndpoint}/monitor/gf3-sarscape-clean`, {
        method: 'POST',
        credentials: 'include',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ dry_run: false, require_standardized: true }),
      });
      const data = await parseJsonSafe(res, {});
      if (res.ok) {
        setGf3Message(data.message || 'GF3 SARscape 清理任务已启动');
        if (onTaskStart) {
          onTaskStart(data.task_id, 'GF3 SARscape 中间数据清理已启动。', {
            nonBlocking: true,
            taskType: 'GF3_SARSCAPE_CLEAN',
          });
        }
      } else {
        setGf3Message(`失败：${data.detail || '未知错误'}`);
      }
    } catch (err) {
      setGf3Message(`失败：${err.message || '未知错误'}`);
    } finally {
      setGf3SarscapeCleanLoading(false);
    }
  };

  const handleOpenUnpackDialog = () => {
    if (readOnly) {
      setUnpackMessage('当前账户为只读模式，无法触发解包任务。');
      return;
    }
    setUnpackDialogError('');
    setUnpackRunOptions(createUnpackRunOptions(unpackConfig));
    setShowUnpackDialog(true);
  };

  const handleCloseUnpackDialog = () => {
    if (unpackLoading) {
      return;
    }
    setShowUnpackDialog(false);
    setUnpackDialogError('');
  };

  const handleUnpackOptionChange = (field, value) => {
    setUnpackRunOptions((prev) => ({
      ...prev,
      [field]: value,
    }));
  };

  const handleUnpackRun = async () => {
    if (readOnly) {
      setUnpackMessage('当前账户为只读模式，无法触发解包任务。');
      return;
    }

    let payload;
    try {
      payload = {
        max_files_per_run: parseUnpackRunValue(unpackRunOptions.max_files_per_run, '单次解包数量'),
        max_runtime_minutes: parseUnpackRunValue(unpackRunOptions.max_runtime_minutes, '最长运行时间'),
      };
    } catch (err) {
      const errorText = err instanceof Error ? err.message : '解包参数校验失败';
      setUnpackDialogError(errorText);
      setUnpackMessage(`失败：${errorText}`);
      return;
    }

    setUnpackDialogError('');
    setUnpackLoading(true);
    setUnpackMessage('LT-1 解包任务启动中...');
    try {
      const res = await fetch(`${apiEndpoint}/unpack/run`, {
        method: 'POST',
        credentials: 'include',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(payload),
      });
      const data = await parseJsonSafe(res, {});
      if (res.ok) {
        setShowUnpackDialog(false);
        setUnpackTaskId(data.task_id || '');
        setUnpackTaskTerminal(false);
        setUnpackMessage(data.message || 'LT-1 解包任务已启动');
        if (onTaskStart) {
          onTaskStart(data.task_id, 'LT-1 解包任务已启动。', {
            nonBlocking: true,
            taskType: 'UNPACK_ARCHIVES',
          });
        }
      } else {
        const errorText = data.detail || '未知错误';
        setUnpackDialogError(errorText);
        setUnpackMessage(`失败：${errorText}`);
      }
    } catch (err) {
      const errorText = err.message || '未知错误';
      setUnpackDialogError(errorText);
      setUnpackMessage(`失败：${errorText}`);
    } finally {
      setUnpackLoading(false);
    }
  };

  const handleRadarScan = async () => {
    if (readOnly) {
      setUnpackMessage('当前账户为只读模式，无法触发扫描。');
      return;
    }
    setUnpackMessage('LT-1 扫描启动中...');
    try {
      const res = await fetch(`${apiEndpoint}/monitor/run-now?target=radar`, {
        method: 'POST',
        credentials: 'include',
      });
      const data = await parseJsonSafe(res, {});
      if (res.ok) {
        setUnpackMessage(data.message || 'LT-1 扫描任务已启动');
        if (onTaskStart) {
          onTaskStart(data.task_id, '已触发 LT-1 手动扫描...');
        }
      } else {
        setUnpackMessage(`失败：${data.detail || '未知错误'}`);
      }
    } catch (err) {
      setUnpackMessage(`失败：${err.message || '未知错误'}`);
    }
  };

  const handleOrbitScan = async () => {
    if (readOnly) {
      setUnpackMessage('当前账户为只读模式，无法触发扫描。');
      return;
    }
    setUnpackMessage('精轨扫描启动中...');
    try {
      const res = await fetch(`${apiEndpoint}/monitor/run-now?target=orbit`, {
        method: 'POST',
        credentials: 'include',
      });
      const data = await parseJsonSafe(res, {});
      if (res.ok) {
        setUnpackMessage(data.message || '精轨扫描任务已启动');
        if (onTaskStart) {
          onTaskStart(data.task_id, '已触发精轨手动扫描...');
        }
      } else {
        setUnpackMessage(`失败：${data.detail || '未知错误'}`);
      }
    } catch (err) {
      setUnpackMessage(`失败：${err.message || '未知错误'}`);
    }
  };

  const handleGf3Scan = async () => {
    if (readOnly) {
      setGf3Message('当前账户为只读模式，无法触发扫描。');
      return;
    }
    setGf3ScanLoading(true);
    setGf3Message('GF3 扫描启动中...');
    try {
      const res = await fetch(`${apiEndpoint}/monitor/run-now?target=gf3`, {
        method: 'POST',
        credentials: 'include',
      });
      const data = await parseJsonSafe(res, {});
      if (res.ok) {
        setGf3Message(data.message || 'GF3 扫描任务已启动');
        if (onTaskStart) {
          onTaskStart(data.task_id, '已触发 GF3 手动扫描...');
        }
      } else {
        setGf3Message(`失败：${data.detail || '未知错误'}`);
      }
    } catch (err) {
      setGf3Message(`失败：${err.message || '未知错误'}`);
    } finally {
      setGf3ScanLoading(false);
    }
  };

  const sectionStyle = {
    marginBottom: '12px',
    padding: '10px 12px',
    borderRadius: '10px',
    background: 'var(--color-panel-bg)',
    border: '1px solid var(--color-border)',
    boxShadow: 'var(--shadow-soft)',
  };
  const labelStyle = { minWidth: '100px', color: 'var(--color-text-muted)', flexShrink: 0 };
  const rowStyle = { display: 'flex', gap: '8px' };
  const gridStyle = { display: 'grid', rowGap: '6px', fontSize: '0.9em', color: 'var(--color-text-secondary)' };

  const actionBtnStyle = (isLoading, isDisabled) => ({
    padding: '6px 10px',
    backgroundColor: 'var(--color-accent)',
    color: 'white',
    border: 'none',
    borderRadius: '4px',
    cursor: isLoading || isDisabled ? 'not-allowed' : 'pointer',
    fontSize: '0.85em',
  });

  return (
    <div
      className="monitor-panel"
      style={{
        padding: '15px',
        backgroundColor: 'var(--color-panel-bg)',
        borderTop: '1px solid var(--color-border)',
        display: 'flex',
        flexDirection: 'column',
        height: '100%',
        overflow: 'hidden',
      }}
    >
      <h3 style={{ marginTop: 0, marginBottom: '8px', fontSize: '1.1em', flexShrink: 0 }}>数据监控面板</h3>

      <div style={{ flex: 1, overflowY: 'auto', minHeight: 0, paddingRight: '4px' }}>
        <div
          style={{
            margin: '0 0 12px',
            padding: '10px 12px',
            borderRadius: '8px',
            background: 'linear-gradient(90deg, var(--color-accent-soft) 0%, #fff 70%)',
            border: '1px solid #c7ddff',
            color: 'var(--color-accent-strong)',
            fontSize: '0.9em',
          }}
        >
          {configLoaded
            ? '仅手动模式。路径从 .env 读取；如需修改请更新 .env 并重启后端。'
            : '未加载到监控状态，请检查后端 /api/monitor/status。'}
        </div>

        <div style={sectionStyle}>
          <div style={{ fontWeight: 'bold', marginBottom: '8px', color: 'var(--color-text-primary)' }}>路径摘要</div>
          <div style={gridStyle}>
            <div style={rowStyle}><span style={labelStyle}>LT-1 存储</span><span style={{ wordBreak: 'break-all' }}>{formatList(config.radar_dirs)}</span></div>
            <div style={rowStyle}><span style={labelStyle}>LT-1 精轨</span><span style={{ wordBreak: 'break-all' }}>{config.orbit_dir || '未配置'}</span></div>
            <div style={rowStyle}><span style={labelStyle}>S1 源数据</span><span style={{ wordBreak: 'break-all' }}>{formatList(config.s1_source_dirs)}</span></div>
            <div style={rowStyle}><span style={labelStyle}>S1 存储</span><span style={{ wordBreak: 'break-all' }}>{formatList(config.s1_storage_dirs)}</span></div>
            <div style={rowStyle}><span style={labelStyle}>S1 精轨</span><span style={{ wordBreak: 'break-all' }}>{formatList(config.s1_orbit_dirs)}</span></div>
            <div style={rowStyle}><span style={labelStyle}>GF3 压缩包</span><span style={{ wordBreak: 'break-all' }}>{formatList(config.gf3_archive_source_dirs)}</span></div>
            <div style={rowStyle}><span style={labelStyle}>GF3 来源</span><span style={{ wordBreak: 'break-all' }}>{formatList(config.gf3_source_dirs)}</span></div>
            <div style={rowStyle}><span style={labelStyle}>GF3 原生</span><span style={{ wordBreak: 'break-all' }}>{formatList(config.gf3_sarscape_native_dirs)}</span></div>
            <div style={rowStyle}><span style={labelStyle}>GF3 存储</span><span style={{ wordBreak: 'break-all' }}>{formatList(config.gf3_storage_dirs)}</span></div>
            <div style={rowStyle}><span style={labelStyle}>D-InSAR 结果</span><span style={{ wordBreak: 'break-all' }}>{formatList(config.dinsar_dirs)}</span></div>
          </div>
        </div>

        <div style={sectionStyle}>
          <div style={{ fontWeight: 'bold', marginBottom: '8px', color: 'var(--color-text-primary)' }}>LT-1 归档解包 / 扫描</div>
          <div style={{ ...gridStyle, marginBottom: '8px' }}>
            <div style={rowStyle}><span style={labelStyle}>来源目录</span><span style={{ wordBreak: 'break-all' }}>{formatList(unpackConfig.source_dirs)}</span></div>
            <div style={rowStyle}><span style={labelStyle}>LT-1 存储</span><span style={{ wordBreak: 'break-all' }}>{formatList(unpackConfig.insar_storage_dirs)}</span></div>
            <div style={rowStyle}><span style={labelStyle}>单次上限</span><span>{unpackConfig.max_files_per_run > 0 ? `${unpackConfig.max_files_per_run} 个压缩包` : '不限'}</span></div>
            <div style={rowStyle}><span style={labelStyle}>最长运行</span><span>{unpackConfig.max_runtime_minutes > 0 ? `${unpackConfig.max_runtime_minutes} 分钟` : '不限'}</span></div>
          </div>
          <div style={{ display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
            <button
              onClick={handleOpenUnpackDialog}
              disabled={unpackLoading || !canOpenUnpackDialog}
              style={actionBtnStyle(unpackLoading, !canOpenUnpackDialog)}
            >
              {unpackLoading ? '运行中...' : (readOnly ? '只读模式' : 'LT-1 解包')}
            </button>
            <button
              onClick={handleRadarScan}
              disabled={readOnly || !canRunRadar}
              style={actionBtnStyle(false, !canRunRadar)}
            >
              {readOnly ? '只读模式' : '扫描 LT-1'}
            </button>
            <button
              onClick={handleOrbitScan}
              disabled={readOnly || !canRunOrbit}
              style={actionBtnStyle(false, !canRunOrbit)}
            >
              {readOnly ? '只读模式' : '扫描精轨'}
            </button>
            <div
              style={{
                fontSize: '0.85em',
                color: unpackMessage.includes('失败') ? 'var(--color-danger)' : 'var(--color-text-muted)',
                alignSelf: 'center',
              }}
            >
              {unpackMessage}
            </div>
          </div>
        </div>

        <div style={sectionStyle}>
          <div style={{ fontWeight: 'bold', marginBottom: '8px', color: 'var(--color-text-primary)' }}>Sentinel-1 解包 / 扫描</div>
          <div style={{ ...gridStyle, marginBottom: '8px' }}>
            <div style={rowStyle}><span style={labelStyle}>S1 源数据</span><span style={{ wordBreak: 'break-all' }}>{formatList(config.s1_source_dirs)}</span></div>
            <div style={rowStyle}><span style={labelStyle}>S1 存储</span><span style={{ wordBreak: 'break-all' }}>{formatList(config.s1_storage_dirs)}</span></div>
            <div style={rowStyle}><span style={labelStyle}>S1 精轨</span><span style={{ wordBreak: 'break-all' }}>{formatList(config.s1_orbit_dirs)}</span></div>
          </div>
          <div style={{ display: 'flex', gap: '10px' }}>
            <button
              onClick={handleS1Run}
              disabled={s1Loading || s1ScanLoading || !canRunS1}
              style={actionBtnStyle(s1Loading, !canRunS1)}
            >
              {s1Loading ? '运行中...' : (readOnly ? '只读模式' : 'Sentinel-1 解包')}
            </button>
            <button
              onClick={handleS1Scan}
              disabled={s1ScanLoading || s1Loading || !canRunS1Scan}
              style={actionBtnStyle(s1ScanLoading, !canRunS1Scan)}
            >
              {s1ScanLoading ? '运行中...' : (readOnly ? '只读模式' : '扫描 S1 源数据')}
            </button>
            <button
              onClick={handleS1OrbitScan}
              disabled={s1ScanLoading || s1Loading || !canRunS1OrbitScan}
              style={actionBtnStyle(s1ScanLoading, !canRunS1OrbitScan)}
            >
              {s1ScanLoading ? '运行中...' : (readOnly ? '只读模式' : '扫描 S1 精轨')}
            </button>
            <div
              style={{
                fontSize: '0.85em',
                color: s1Message.includes('失败') ? 'var(--color-danger)' : 'var(--color-text-muted)',
                alignSelf: 'center',
              }}
            >
              {s1ActiveTask ? (s1ActiveTask.message || 'Sentinel-1 任务运行中...') : s1Message}
            </div>
          </div>
        </div>

        <div style={sectionStyle}>
          <div style={{ fontWeight: 'bold', marginBottom: '8px', color: 'var(--color-text-primary)' }}>GF3 归档预处理</div>
          <div style={{ ...gridStyle, marginBottom: '8px' }}>
            <div style={rowStyle}><span style={labelStyle}>压缩包来源</span><span style={{ wordBreak: 'break-all' }}>{formatList(config.gf3_archive_source_dirs)}</span></div>
            <div style={rowStyle}><span style={labelStyle}>L1A 来源</span><span style={{ wordBreak: 'break-all' }}>{formatList(config.gf3_source_dirs)}</span></div>
            <div style={rowStyle}><span style={labelStyle}>SARscape 原生</span><span style={{ wordBreak: 'break-all' }}>{formatList(config.gf3_sarscape_native_dirs)}</span></div>
            <div style={rowStyle}><span style={labelStyle}>L2 存储</span><span style={{ wordBreak: 'break-all' }}>{formatList(config.gf3_storage_dirs)}</span></div>
            <div style={rowStyle}><span style={labelStyle}>Wrapper</span><span style={{ wordBreak: 'break-all' }}>{config.gf3_sarscape_wrapper_exe || '未配置'}</span></div>
            <div style={rowStyle}><span style={labelStyle}>SARscape DEM</span><span style={{ wordBreak: 'break-all' }}>{config.gf3_sarscape_dem_path || '未配置'}</span></div>
            <div style={rowStyle}><span style={labelStyle}>极化</span><span>{config.gf3_sarscape_polarizations || 'HH,HV'}</span></div>
          </div>
          <div style={{ display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
            <button
              onClick={handleGf3Unpack}
              disabled={gf3UnpackLoading || readOnly || !canRunGf3Unpack}
              style={actionBtnStyle(gf3UnpackLoading, readOnly || !canRunGf3Unpack)}
            >
              {gf3UnpackLoading ? '运行中...' : (readOnly ? '只读模式' : 'GF3 解包')}
            </button>
            <button
              onClick={handleGf3BatchProcess}
              disabled={gf3ProcessLoading || readOnly || !canRunGf3Process}
              style={actionBtnStyle(gf3ProcessLoading, readOnly || !canRunGf3Process)}
            >
              {gf3ProcessLoading ? '运行中...' : (readOnly ? '只读模式' : 'GF3 预处理')}
            </button>
            <button
              onClick={handleGf3SarscapeProduce}
              disabled={gf3SarscapeProduceLoading || readOnly || !canRunGf3SarscapeProduce}
              style={actionBtnStyle(gf3SarscapeProduceLoading, readOnly || !canRunGf3SarscapeProduce)}
            >
              {gf3SarscapeProduceLoading ? '运行中...' : (readOnly ? '只读模式' : 'GF3 SARscape 生产')}
            </button>
            <button
              onClick={handleGf3SarscapeSync}
              disabled={gf3SarscapeSyncLoading || readOnly || !canRunGf3SarscapeSync}
              style={actionBtnStyle(gf3SarscapeSyncLoading, readOnly || !canRunGf3SarscapeSync)}
            >
              {gf3SarscapeSyncLoading ? '运行中...' : (readOnly ? '只读模式' : 'GF3 SARscape 入库')}
            </button>
            <button
              onClick={handleGf3SarscapeClean}
              disabled={gf3SarscapeCleanLoading || readOnly || !canRunGf3SarscapeClean}
              style={actionBtnStyle(gf3SarscapeCleanLoading, readOnly || !canRunGf3SarscapeClean)}
            >
              {gf3SarscapeCleanLoading ? '运行中...' : (readOnly ? '只读模式' : '清理 GF3 中间')}
            </button>
            <button
              onClick={handleGf3Scan}
              disabled={gf3ScanLoading || readOnly || !canRunGf3Scan}
              style={actionBtnStyle(gf3ScanLoading, readOnly || !canRunGf3Scan)}
            >
              {gf3ScanLoading ? '运行中...' : (readOnly ? '只读模式' : '扫描 GF3')}
            </button>
            <div
              style={{
                fontSize: '0.85em',
                color: gf3Message.includes('失败') ? 'var(--color-danger)' : 'var(--color-text-muted)',
                alignSelf: 'center',
              }}
            >
              {gf3ActiveTask ? (gf3ActiveTask.message || 'GF3 任务运行中...') : gf3Message}
            </div>
          </div>
        </div>
      </div>

      <div style={{ flexShrink: 0, borderTop: '1px solid var(--color-border)', paddingTop: '10px', marginTop: '6px' }}>
        <div style={{ fontWeight: 'bold', marginBottom: '6px', color: 'var(--color-text-primary)' }}>实时日志</div>
        <div
          style={{
            height: '160px',
            overflowY: 'auto',
            backgroundColor: '#0f172a',
            color: '#22c55e',
            padding: '10px',
            fontFamily: 'monospace',
            fontSize: '0.85em',
            borderRadius: '4px',
          }}
        >
          {displayLogs.length === 0 ? (
            <div style={{ color: 'var(--color-text-muted)' }}>暂无日志...</div>
          ) : (
            displayLogs.map((log, index) => (
              <div key={index} style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}>{t(log)}</div>
            ))
          )}
          <div ref={logEndRef} />
        </div>
      </div>

      {showUnpackDialog && (
        <div className="modal-overlay visible" onClick={handleCloseUnpackDialog}>
          <div className="modal-content" onClick={(event) => event.stopPropagation()}>
            <h3 style={{ marginTop: 0 }}>LT-1 解包任务参数</h3>
            <form
              onSubmit={(event) => {
                event.preventDefault();
                handleUnpackRun();
              }}
            >
              <div
                style={{
                  marginBottom: '14px',
                  padding: '10px 12px',
                  borderRadius: '8px',
                  background: 'var(--color-panel-muted)',
                  border: '1px solid var(--color-border)',
                  fontSize: '0.9em',
                  color: 'var(--color-text-secondary)',
                  lineHeight: 1.7,
                }}
              >
                本次填写的参数只覆盖当前这一次解包任务，不会修改 `.env` 默认值。输入 `0` 表示不限。
              </div>

              <div style={{ ...gridStyle, marginBottom: '14px' }}>
                <div style={rowStyle}><span style={labelStyle}>来源目录</span><span style={{ wordBreak: 'break-all' }}>{formatList(unpackConfig.source_dirs)}</span></div>
                <div style={rowStyle}><span style={labelStyle}>LT-1 存储</span><span style={{ wordBreak: 'break-all' }}>{formatList(unpackConfig.insar_storage_dirs)}</span></div>
              </div>

              <div className="form-group">
                <label>单次最多解包数量</label>
                <input
                  type="number"
                  min="0"
                  step="1"
                  value={unpackRunOptions.max_files_per_run}
                  onChange={(event) => handleUnpackOptionChange('max_files_per_run', event.target.value)}
                  disabled={unpackLoading}
                />
              </div>

              <div className="form-group">
                <label>最长运行时间（分钟）</label>
                <input
                  type="number"
                  min="0"
                  step="1"
                  value={unpackRunOptions.max_runtime_minutes}
                  onChange={(event) => handleUnpackOptionChange('max_runtime_minutes', event.target.value)}
                  disabled={unpackLoading}
                />
              </div>

              {unpackDialogError && (
                <div
                  style={{
                    marginTop: '6px',
                    color: 'var(--color-danger)',
                    fontSize: '0.9em',
                    wordBreak: 'break-all',
                  }}
                >
                  {unpackDialogError}
                </div>
              )}

              <div className="modal-actions">
                <button type="button" onClick={handleCloseUnpackDialog} disabled={unpackLoading}>
                  取消
                </button>
                <button type="submit" disabled={unpackLoading}>
                  {unpackLoading ? '启动中...' : '启动解包任务'}
                </button>
              </div>
            </form>
          </div>
        </div>
      )}
    </div>
  );
};

export default DataMonitorPanel;
