import 'dart:io';

import 'package:excel/excel.dart';

import '../models/program.dart';
import '../models/step.dart';
import '../services/program_service.dart';
import 'excel_template_service.dart';

/// Excel 导入服务
///
/// 解析用户填好的 .xlsx 并通过 [ProgramService] 写入数据库。
/// 模板结构与 [ExcelTemplateService] 一致：Programs + Steps 双表，
/// 通过 program_code 关联。
class ExcelImportService {
  static final ExcelImportService instance = ExcelImportService._internal();
  final ProgramService _programService = ProgramService.instance;

  ExcelImportService._internal();

  /// 从 .xlsx 文件导入程序，返回成功导入的程序数量
  Future<int> importFromExcel(File file) async {
    final bytes = await file.readAsBytes();
    final excel = Excel.decodeBytes(bytes);

    final programsSheet = _findSheet(excel, ExcelTemplateService.sheetPrograms);
    if (programsSheet == null) {
      throw const ExcelImportException('缺少 Programs 工作表');
    }

    final programs = _parsePrograms(programsSheet);
    if (programs.isEmpty) {
      throw const ExcelImportException('Programs 表无有效数据');
    }

    // 读取已有 code，避免重复
    final existing = await _programService.getAllPrograms();
    final existingCodes = existing.map((p) => p.code).toSet();

    // 解析步骤
    final stepsSheet = _findSheet(excel, ExcelTemplateService.sheetSteps);
    final stepsByCode = stepsSheet == null
        ? <String, List<_RawStep>>{}
        : _parseSteps(stepsSheet);

    int importedCount = 0;
    for (final program in programs) {
      try {
        if (existingCodes.contains(program.code)) {
          continue;
        }

        final programId = await _programService.addProgram(program);

        final rawSteps = stepsByCode[program.code] ?? const <_RawStep>[];
        // 按 step_no 排序后写入
        rawSteps.sort((a, b) => a.stepNo.compareTo(b.stepNo));
        for (var i = 0; i < rawSteps.length; i++) {
          final raw = rawSteps[i];
          final step = Step(
            programId: programId,
            stepNo: i + 1,
            position: raw.position,
            name: raw.name,
            mixTime: raw.mixTime,
            magnetTime: raw.magnetTime,
            volume: raw.volume,
            blowTime: raw.blowTime,
            speed: raw.speed,
          );
          await _programService.addStep(step);
        }

        importedCount++;
      } catch (_) {
        // 单条失败不影响其他程序
        continue;
      }
    }

    return importedCount;
  }

  Sheet? _findSheet(Excel excel, String name) {
    for (final entry in excel.tables.entries) {
      if (entry.key == name) return entry.value;
    }
    return null;
  }

  /// 解析 Programs 表
  /// 返回不含 id 的 Program 列表（createdAt 由调用方填充）
  List<Program> _parsePrograms(Sheet sheet) {
    final rows = _dataRows(sheet);
    final results = <Program>[];

    for (final cells in rows) {
      final code = _readString(cells, 0);
      final name = _readString(cells, 1);
      if (code.isEmpty || name.isEmpty) continue;

      results.add(
        Program(
          code: code,
          name: name,
          createdAt: DateTime.now().toString().split('.').first,
          status: _readInt(cells, 4, 1) == 0 ? 0 : 1,
          temperature: _readInt(cells, 2, 50),
          airflowTime: _readInt(cells, 3, 60),
        ),
      );
    }
    return results;
  }

  /// 解析 Steps 表
  /// 以 program_code 为 key 分组
  Map<String, List<_RawStep>> _parseSteps(Sheet sheet) {
    final rows = _dataRows(sheet);
    final map = <String, List<_RawStep>>{};

    for (final cells in rows) {
      final programCode = _readString(cells, 0);
      if (programCode.isEmpty) continue;
      final position = _readString(cells, 2, 'A1');
      final name = _readString(cells, 3);
      if (name.isEmpty) continue;

      final raw = _RawStep(
        stepNo: _readInt(cells, 1, 0),
        position: position,
        name: name,
        mixTime: _readInt(cells, 4, 0),
        magnetTime: _readInt(cells, 5, 0),
        volume: _readInt(cells, 6, 0),
        blowTime: _readInt(cells, 7, 0),
        speed: _readInt(cells, 8, 5),
      );
      map.putIfAbsent(programCode, () => []).add(raw);
    }
    return map;
  }

  /// 跳过表头和说明行（首行表头，后续以"说明"开头的视为说明）
  List<List<Object?>> _dataRows(Sheet sheet) {
    final result = <List<Object?>>[];
    for (var i = 1; i < sheet.rows.length; i++) {
      final row = sheet.rows[i];
      // 跳过空行
      if (row.every((c) => c == null || c.value == null)) continue;
      final firstCell = _asTrimmed(row.first?.value);
      if (firstCell.startsWith('说明')) continue;
      result.add(row.map((c) => c?.value).toList(growable: false));
    }
    return result;
  }

  String _readString(List<Object?> row, int index, [String fallback = '']) {
    if (index >= row.length) return fallback;
    final v = row[index];
    if (v == null) return fallback;
    final s = v.toString().trim();
    return s.isEmpty ? fallback : s;
  }

  int _readInt(List<Object?> row, int index, int fallback) {
    if (index >= row.length) return fallback;
    final v = row[index];
    if (v == null) return fallback;
    if (v is int) return v;
    if (v is double) return v.toInt();
    final parsed = int.tryParse(v.toString().trim());
    return parsed ?? fallback;
  }

  String _asTrimmed(Object? v) {
    if (v == null) return '';
    return v.toString().trim();
  }
}

class _RawStep {
  final int stepNo;
  final String position;
  final String name;
  final int mixTime;
  final int magnetTime;
  final int volume;
  final int blowTime;
  final int speed;

  _RawStep({
    required this.stepNo,
    required this.position,
    required this.name,
    required this.mixTime,
    required this.magnetTime,
    required this.volume,
    required this.blowTime,
    required this.speed,
  });
}

/// Excel 导入异常
class ExcelImportException implements Exception {
  final String message;
  const ExcelImportException(this.message);

  @override
  String toString() => message;
}
