import 'package:excel/excel.dart';

/// 엑셀 파일에서 이벤트 데이터를 파싱하는 유틸리티 클래스
class EventExcelParser {
  /// 엑셀 파일 바이트 데이터에서 이벤트 데이터 목록을 추출합니다.
  /// 
  /// [bytes] 엑셀 파일의 바이트 데이터
  /// 
  /// 반환값:
  /// - processedRows: 처리된 총 행 수
  /// - validEvents: 유효한 이벤트 데이터 목록
  /// - invalidRows: 유효하지 않은 행 수
  static Map<String, dynamic> parseExcelBytes(List<int> bytes) {
    final excel = Excel.decodeBytes(bytes);
    final events = <Map<String, dynamic>>[];
    int invalidRows = 0;
    int processedRows = 0;
    final List<int> invalidRowIndices = [];
    final Map<int, String> invalidRowReasons = {};

    // 첫 번째 시트 사용
    final sheet = excel.tables.keys.first;
    final rows = excel.tables[sheet]?.rows;

    if (rows == null || rows.isEmpty) {
      return {
        'processedRows': 0,
        'validEvents': [],
        'invalidRows': 0,
        'error': '엑셀 파일에 데이터가 없습니다.'
      };
    }

    // 헤더 행 추출 (첫 번째 행)
    final headers = <String>[];
    for (final cell in rows[0]) {
      if (cell?.value != null) {
        headers.add(cell!.value.toString().trim().toLowerCase());
      }
    }

    // 필수 필드 확인
    if (!headers.contains('title') || !headers.contains('startdate')) {
      return {
        'processedRows': 0,
        'validEvents': [],
        'invalidRows': 0,
        'error': '필수 필드(title, startDate)가 없습니다.'
      };
    }

    // 데이터 행 처리 (헤더 제외)
    for (var i = 1; i < rows.length; i++) {
      processedRows++;
      final row = rows[i];
      final event = <String, dynamic>{};

      // 각 셀 처리
      for (var j = 0; j < headers.length && j < row.length; j++) {
        final header = headers[j];

        // 날짜 필드 특별 처리
        if (header == 'startdate' || header == 'enddate') {
          DateTime? date = _parseDate(row[j]?.value);

          // 날짜 값 설정: 파싱 성공 시만 값 지정, 실패 시 null 유지
          final normalizedHeader = header == 'startdate' ? 'startDate' : 'endDate';
          event[normalizedHeader] = (date != null) ? date.toIso8601String() : null;
        } else {
          // 문자열/일반 필드: excel v4의 TextCellValue 등 실제 값 추출
          String raw = '';
          final cellVal = row[j]?.value;
          if (cellVal is TextCellValue) {
            raw = cellVal.value.toString();
          } else if (cellVal != null) {
            raw = cellVal.toString();
          }
          final stringValue = raw.trim();

          // 헤더 이름 정규화 (특별한 경우)
          String normalizedHeader = header;
          if (header == 'title' || header == 'description' || header == 'location' || 
              header == 'status' || header == 'type' || header == 'maxparticipants') {
            normalizedHeader = header == 'maxparticipants' ? 'maxParticipants' : header;
          }

          // 빈 문자열은 null로 처리
          event[normalizedHeader] = stringValue.isEmpty ? null : stringValue;
        }
      }

      // 필수 필드가 있는 경우만 추가
      final hasTitle = event.containsKey('title') && (event['title']?.toString().trim().isNotEmpty ?? false);
      final hasStart = event.containsKey('startDate') && (event['startDate']?.toString().trim().isNotEmpty ?? false);
      if (hasTitle && hasStart) {
        events.add(event);
      } else {
        invalidRows++;
        // 데이터 행 기준(헤더 제외) 1-based가 아닌, 테스트 기대값에 맞춰 i 사용
        // 즉, 헤더가 0, 첫 데이터 행이 i=1이므로 무효 행 번호로 i를 기록
        final rowNo = i;
        invalidRowIndices.add(rowNo);
        final reasons = <String>[];
        if (!hasTitle) reasons.add('title 누락');
        if (!hasStart) reasons.add('startDate 누락');
        invalidRowReasons[rowNo] = reasons.join(', ');
      }
    }

    return {
      'processedRows': processedRows,
      'validEvents': events,
      'invalidRows': invalidRows,
      'invalidRowIndices': invalidRowIndices,
      'invalidRowReasons': invalidRowReasons,
      'error': events.isEmpty ? '유효한 이벤트 데이터가 없습니다.' : null
    };
  }

  /// 다양한 형식의 날짜 값을 DateTime 객체로 파싱합니다.
  static DateTime? _parseDate(dynamic value) {
    DateTime? date;
    
    // DateTime 타입인 경우
    if (value is DateTime) {
      return value;
    } 
    
    // 문자열인 경우
    if (value != null) {
      final strValue = value.toString();
      
      if (strValue.isNotEmpty) {
        // YYYY-MM-DD 형식 시도
        try {
          date = DateTime.parse(strValue);
        } catch (_) {
          // 실패 시 다른 형식 시도
        }
        
        // YYYY/MM/DD 형식 시도
        if (date == null && strValue.contains('/')) {
          try {
            final parts = strValue.split('/');
            if (parts.length == 3) {
              date = DateTime(
                int.parse(parts[0]),
                int.parse(parts[1]),
                int.parse(parts[2]),
              );
            }
          } catch (_) {
            // 실패 시 무시
          }
        }
      }
    }
    
    return date;
  }
}
