import 'package:flutter/material.dart'; import 'package:superport/data/models/maintenance_dto.dart'; import 'package:superport/domain/usecases/maintenance_usecase.dart'; /// 정비 우선순위 enum MaintenancePriority { low, medium, high } /// 정비 스케줄 상태 enum MaintenanceScheduleStatus { scheduled, inProgress, completed, overdue, cancelled } /// 정비 스케줄 모델 (UI 전용) class MaintenanceSchedule { final String id; final String title; final DateTime date; final MaintenancePriority priority; final MaintenanceScheduleStatus status; final String description; MaintenanceSchedule({ required this.id, required this.title, required this.date, required this.priority, required this.status, required this.description, }); } /// 유지보수 컨트롤러 (백엔드 API 완전 호환) class MaintenanceController extends ChangeNotifier { final MaintenanceUseCase _maintenanceUseCase; // 상태 관리 List _maintenances = []; bool _isLoading = false; String? _error; // 페이지네이션 int _currentPage = 1; int _totalCount = 0; int _totalPages = 0; static const int _perPage = 20; // 필터 (백엔드 API와 일치) int? _equipmentId; String? _maintenanceType; bool? _isExpired; int? _expiringDays; bool _includeDeleted = false; // 검색 및 정렬 String _searchQuery = ''; String _sortField = 'startedAt'; bool _sortAscending = false; // 선택된 유지보수 MaintenanceDto? _selectedMaintenance; // 만료 예정 유지보수 List _expiringMaintenances = []; // Form 상태 bool _isFormLoading = false; MaintenanceController({required MaintenanceUseCase maintenanceUseCase}) : _maintenanceUseCase = maintenanceUseCase; // Getters List get maintenances => _maintenances; bool get isLoading => _isLoading; bool get isFormLoading => _isFormLoading; String? get error => _error; int get currentPage => _currentPage; int get totalPages => _totalPages; int get totalCount => _totalCount; MaintenanceDto? get selectedMaintenance => _selectedMaintenance; List get expiringMaintenances => _expiringMaintenances; // Filter getters int? get equipmentId => _equipmentId; String? get maintenanceType => _maintenanceType; bool? get isExpired => _isExpired; int? get expiringDays => _expiringDays; bool get includeDeleted => _includeDeleted; String get searchQuery => _searchQuery; String get sortField => _sortField; bool get sortAscending => _sortAscending; /// 유지보수 목록 로드 Future loadMaintenances({bool refresh = false}) async { if (refresh) { _currentPage = 1; _maintenances.clear(); } _isLoading = true; _error = null; notifyListeners(); try { final response = await _maintenanceUseCase.getMaintenances( page: _currentPage, perPage: _perPage, equipmentId: _equipmentId, maintenanceType: _maintenanceType, isExpired: _isExpired, expiringDays: _expiringDays, includeDeleted: _includeDeleted, ); if (refresh) { _maintenances = response.items; } else { _maintenances.addAll(response.items); } _totalCount = response.totalCount; _totalPages = response.totalPages; } catch (e) { _error = e.toString(); } finally { _isLoading = false; notifyListeners(); } } /// 유지보수 상세 조회 Future getMaintenanceDetail(int id) async { try { _isLoading = true; notifyListeners(); final maintenance = await _maintenanceUseCase.getMaintenanceDetail(id); _selectedMaintenance = maintenance; return maintenance; } catch (e) { _error = '유지보수 상세 조회 실패: ${e.toString()}'; return null; } finally { _isLoading = false; notifyListeners(); } } /// 유지보수 생성 Future createMaintenance({ int? equipmentHistoryId, required DateTime startedAt, required DateTime endedAt, required int periodMonth, required String maintenanceType, }) async { _isFormLoading = true; _error = null; notifyListeners(); try { final request = MaintenanceRequestDto( equipmentHistoryId: equipmentHistoryId, startedAt: startedAt, endedAt: endedAt, periodMonth: periodMonth, maintenanceType: maintenanceType, ); final newMaintenance = await _maintenanceUseCase.createMaintenance(request); // 리스트 업데이트 _maintenances.insert(0, newMaintenance); _totalCount++; return true; } catch (e) { _error = '유지보수 생성 실패: ${e.toString()}'; return false; } finally { _isFormLoading = false; notifyListeners(); } } /// 유지보수 수정 Future updateMaintenance({ required int id, DateTime? startedAt, DateTime? endedAt, int? periodMonth, String? maintenanceType, }) async { _isFormLoading = true; _error = null; notifyListeners(); try { final request = MaintenanceUpdateRequestDto( startedAt: startedAt, endedAt: endedAt, periodMonth: periodMonth, maintenanceType: maintenanceType, ); final updatedMaintenance = await _maintenanceUseCase.updateMaintenance(id, request); // 리스트 업데이트 final index = _maintenances.indexWhere((m) => m.id == id); if (index != -1) { _maintenances[index] = updatedMaintenance; } // 선택된 항목 업데이트 if (_selectedMaintenance != null && _selectedMaintenance!.id == id) { _selectedMaintenance = updatedMaintenance; } return true; } catch (e) { _error = '유지보수 수정 실패: ${e.toString()}'; return false; } finally { _isFormLoading = false; notifyListeners(); } } /// 유지보수 삭제 (Soft Delete) Future deleteMaintenance(int id) async { _isFormLoading = true; _error = null; notifyListeners(); try { await _maintenanceUseCase.deleteMaintenance(id); // 리스트에서 제거 _maintenances.removeWhere((m) => m.id == id); _totalCount--; // 선택된 항목 해제 if (_selectedMaintenance != null && _selectedMaintenance!.id == id) { _selectedMaintenance = null; } return true; } catch (e) { _error = '유지보수 삭제 실패: ${e.toString()}'; return false; } finally { _isFormLoading = false; notifyListeners(); } } /// 만료 예정 유지보수 조회 Future loadExpiringMaintenances({int days = 30}) async { try { _expiringMaintenances = await _maintenanceUseCase.getExpiringMaintenances(days: days); notifyListeners(); } catch (e) { _error = '만료 예정 유지보수 조회 실패: ${e.toString()}'; notifyListeners(); } } /// 특정 장비의 유지보수 조회 Future loadMaintenancesByEquipment(int equipmentId) async { _equipmentId = equipmentId; await loadMaintenances(refresh: true); } /// 활성 유지보수만 조회 Future loadActiveMaintenances() async { _includeDeleted = false; await loadMaintenances(refresh: true); } /// 만료된 유지보수 조회 Future loadExpiredMaintenances() async { _isExpired = true; await loadMaintenances(refresh: true); } // 필터 설정 메서드들 void setEquipmentFilter(int? equipmentId) { if (_equipmentId != equipmentId) { _equipmentId = equipmentId; loadMaintenances(refresh: true); } } void setMaintenanceTypeFilter(String? maintenanceType) { if (_maintenanceType != maintenanceType) { _maintenanceType = maintenanceType; loadMaintenances(refresh: true); } } void setExpiredFilter(bool? isExpired) { if (_isExpired != isExpired) { _isExpired = isExpired; loadMaintenances(refresh: true); } } void setExpiringDaysFilter(int? days) { if (_expiringDays != days) { _expiringDays = days; loadMaintenances(refresh: true); } } void setIncludeDeleted(bool includeDeleted) { if (_includeDeleted != includeDeleted) { _includeDeleted = includeDeleted; loadMaintenances(refresh: true); } } /// 모든 필터 초기화 void clearFilters() { _equipmentId = null; _maintenanceType = null; _isExpired = null; _expiringDays = null; _includeDeleted = false; _searchQuery = ''; loadMaintenances(refresh: true); } /// 검색어 설정 void setSearchQuery(String query) { if (_searchQuery != query) { _searchQuery = query; // 검색어가 변경되면 0.5초 후에 검색 실행 (디바운스) Future.delayed(const Duration(milliseconds: 500), () { if (_searchQuery == query) { _filterMaintenancesBySearch(); } }); } } /// 상태 필터 설정 void setMaintenanceFilter(String? status) { switch (status) { case 'active': _isExpired = false; break; case 'completed': case 'expired': _isExpired = true; break; case 'upcoming': _isExpired = false; break; default: _isExpired = null; break; } loadMaintenances(refresh: true); } /// 정렬 설정 void setSorting(String field, bool ascending) { if (_sortField != field || _sortAscending != ascending) { _sortField = field; _sortAscending = ascending; _sortMaintenances(); notifyListeners(); } } /// 검색어로 유지보수 필터링 (로컬 필터링) void _filterMaintenancesBySearch() { if (_searchQuery.trim().isEmpty) { notifyListeners(); return; } // 검색어가 있으면 로컬에서 필터링 final query = _searchQuery.toLowerCase(); // 여기서는 간단히 notifyListeners만 호출 (실제 필터링은 UI에서 수행) notifyListeners(); } /// 유지보수 목록 정렬 void _sortMaintenances() { _maintenances.sort((a, b) { int comparison = 0; switch (_sortField) { case 'startedAt': comparison = a.startedAt.compareTo(b.startedAt); break; case 'endedAt': comparison = a.endedAt.compareTo(b.endedAt); break; case 'maintenanceType': comparison = a.maintenanceType.compareTo(b.maintenanceType); break; case 'periodMonth': comparison = a.periodMonth.compareTo(b.periodMonth); break; default: comparison = a.startedAt.compareTo(b.startedAt); } return _sortAscending ? comparison : -comparison; }); } /// 특정 날짜의 유지보수 스케줄 생성 MaintenanceSchedule? getScheduleForMaintenance(DateTime date) { if (_maintenances.isEmpty) return null; MaintenanceDto? maintenance; try { maintenance = _maintenances.firstWhere( (m) => m.startedAt.year == date.year && m.startedAt.month == date.month && m.startedAt.day == date.day, ); } catch (e) { // 해당 날짜의 정비가 없으면 가장 가까운 정비를 찾거나 null 반환 maintenance = _maintenances.isNotEmpty ? _maintenances.first : null; } if (maintenance == null) return null; return MaintenanceSchedule( id: maintenance.id.toString(), title: _getMaintenanceTitle(maintenance), date: maintenance.startedAt, priority: _getMaintenancePriority(maintenance), status: _getMaintenanceScheduleStatus(maintenance), description: _getMaintenanceDescription(maintenance), ); } String _getMaintenanceTitle(MaintenanceDto maintenance) { final typeDisplay = _getMaintenanceTypeDisplayName(maintenance.maintenanceType); return '$typeDisplay 정비'; } String _getMaintenanceTypeDisplayName(String maintenanceType) { switch (maintenanceType) { case 'WARRANTY': return '무상보증'; case 'CONTRACT': return '유상계약'; case 'INSPECTION': return '점검'; default: return maintenanceType; } } MaintenancePriority _getMaintenancePriority(MaintenanceDto maintenance) { if (maintenance.isExpired) return MaintenancePriority.high; final now = DateTime.now(); final daysUntilStart = maintenance.startedAt.difference(now).inDays; if (daysUntilStart <= 7) return MaintenancePriority.high; if (daysUntilStart <= 30) return MaintenancePriority.medium; return MaintenancePriority.low; } MaintenanceScheduleStatus _getMaintenanceScheduleStatus(MaintenanceDto maintenance) { if (maintenance.isDeleted) return MaintenanceScheduleStatus.cancelled; if (maintenance.isExpired) return MaintenanceScheduleStatus.overdue; final now = DateTime.now(); if (maintenance.startedAt.isAfter(now)) return MaintenanceScheduleStatus.scheduled; if (maintenance.endedAt.isBefore(now)) return MaintenanceScheduleStatus.completed; return MaintenanceScheduleStatus.inProgress; } String _getMaintenanceDescription(MaintenanceDto maintenance) { final status = getMaintenanceStatusText(maintenance); return '상태: $status\n주기: ${maintenance.periodMonth}개월'; } // 페이지네이션 메서드들 void goToPage(int page) { if (page >= 1 && page <= _totalPages && page != _currentPage) { _currentPage = page; loadMaintenances(); } } void nextPage() { if (_currentPage < _totalPages) { _currentPage++; loadMaintenances(); } } void previousPage() { if (_currentPage > 1) { _currentPage--; loadMaintenances(); } } void goToFirstPage() { if (_currentPage != 1) { _currentPage = 1; loadMaintenances(); } } void goToLastPage() { if (_currentPage != _totalPages && _totalPages > 0) { _currentPage = _totalPages; loadMaintenances(); } } // 선택 관리 void selectMaintenance(MaintenanceDto? maintenance) { _selectedMaintenance = maintenance; notifyListeners(); } // 유틸리티 메서드들 String getMaintenanceStatusText(MaintenanceDto maintenance) { if (maintenance.isDeleted) return '삭제됨'; if (maintenance.isExpired) return '만료됨'; final now = DateTime.now(); if (maintenance.startedAt.isAfter(now)) return '예정'; if (maintenance.endedAt.isBefore(now)) return '완료'; return '진행중'; } Color getMaintenanceStatusColor(MaintenanceDto maintenance) { final status = getMaintenanceStatusText(maintenance); switch (status) { case '예정': return Colors.blue; case '진행중': return Colors.green; case '완료': return Colors.grey; case '만료됨': return Colors.red; case '삭제됨': return Colors.grey.withValues(alpha: 0.5); default: return Colors.black; } } // Alert 시스템 (기존 화면 호환성) List get upcomingAlerts => _expiringMaintenances; List get overdueAlerts => _maintenances .where((m) => m.isExpired && m.isActive) .toList(); int get upcomingCount => upcomingAlerts.length; int get overdueCount => overdueAlerts.length; /// Alert 데이터 로드 (기존 화면 호환성) Future loadAlerts() async { await loadExpiringMaintenances(); notifyListeners(); } // 통계 정보 int get activeMaintenanceCount => _maintenances.where((m) => m.isActive).length; int get expiredMaintenanceCount => _maintenances.where((m) => m.isExpired).length; int get warrantyMaintenanceCount => _maintenances.where((m) => m.maintenanceType == 'WARRANTY').length; int get contractMaintenanceCount => _maintenances.where((m) => m.maintenanceType == 'CONTRACT').length; int get inspectionMaintenanceCount => _maintenances.where((m) => m.maintenanceType == 'INSPECTION').length; // 오류 관리 void clearError() { _error = null; notifyListeners(); } // 초기화 void reset() { _maintenances.clear(); _expiringMaintenances.clear(); _selectedMaintenance = null; _currentPage = 1; _totalCount = 0; _totalPages = 0; _equipmentId = null; _maintenanceType = null; _isExpired = null; _expiringDays = null; _includeDeleted = false; _searchQuery = ''; _sortField = 'startedAt'; _sortAscending = false; _error = null; _isLoading = false; _isFormLoading = false; notifyListeners(); } @override void dispose() { reset(); super.dispose(); } }