import 'package:flutter/foundation.dart';
import 'package:superport_v2/core/common/models/paginated_result.dart';
import 'package:superport_v2/core/network/failure.dart';

import '../../domain/entities/approval_step_input.dart';
import '../../domain/entities/approval_step_record.dart';
import '../../domain/repositories/approval_step_repository.dart';

/// 결재 단계 관리 화면을 위한 상태 컨트롤러.
///
/// 단계 목록 조회, 필터링, 단건 생성/수정을 담당한다.
class ApprovalStepController extends ChangeNotifier {
  ApprovalStepController({required ApprovalStepRepository repository})
    : _repository = repository;

  final ApprovalStepRepository _repository;

  PaginatedResult<ApprovalStepRecord>? _result;
  bool _isLoading = false;
  bool _isSaving = false;
  String _query = '';
  int? _statusId;
  int? _approverId;
  String? _errorMessage;
  bool _isLoadingDetail = false;
  ApprovalStepRecord? _selected;

  PaginatedResult<ApprovalStepRecord>? get result => _result;
  bool get isLoading => _isLoading;
  bool get isSaving => _isSaving;
  String get query => _query;
  int? get statusId => _statusId;
  int? get approverId => _approverId;
  String? get errorMessage => _errorMessage;
  bool get isLoadingDetail => _isLoadingDetail;
  ApprovalStepRecord? get selected => _selected;

  /// 단계 목록을 조회한다. 페이지와 검색 조건을 함께 적용한다.
  Future<void> fetch({int page = 1}) async {
    _isLoading = true;
    _errorMessage = null;
    notifyListeners();
    try {
      final previous = _result;
      final int resolvedPage;
      if (page < 1) {
        resolvedPage = 1;
      } else if (previous != null && previous.pageSize > 0) {
        final calculated = (previous.total / previous.pageSize).ceil();
        final maxPage = calculated < 1 ? 1 : calculated;
        resolvedPage = page > maxPage ? maxPage : page;
      } else {
        resolvedPage = page;
      }
      final sanitizedQuery = _query.trim();
      final response = await _repository.list(
        page: resolvedPage,
        pageSize: _result?.pageSize ?? 20,
        query: sanitizedQuery.isEmpty ? null : sanitizedQuery,
        statusId: _statusId,
        approverId: _approverId,
      );
      _result = response;
    } catch (error) {
      final failure = Failure.from(error);
      _errorMessage = failure.describe();
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  /// 검색어를 변경해 다음 조회에 반영한다.
  void updateQuery(String value) {
    _query = value;
    notifyListeners();
  }

  /// 선택한 단계 상태 ID를 갱신한다. null이면 전체 상태를 의미한다.
  void updateStatusId(int? value) {
    _statusId = value;
    notifyListeners();
  }

  /// 승인자 ID 필터를 변경한다. null이면 필터를 해제한다.
  void updateApproverId(int? value) {
    _approverId = value;
    notifyListeners();
  }

  /// 특정 결재 단계의 상세를 조회한다.
  ///
  /// 성공 시 [_selected]에 저장하고, 실패 시 오류 메시지를 기록한다.
  Future<ApprovalStepRecord?> fetchDetail(int id) async {
    _isLoadingDetail = true;
    _errorMessage = null;
    notifyListeners();
    try {
      final detail = await _repository.fetchDetail(id);
      _selected = detail;
      return detail;
    } catch (error) {
      final failure = Failure.from(error);
      _errorMessage = failure.describe();
      return null;
    } finally {
      _isLoadingDetail = false;
      notifyListeners();
    }
  }

  /// 현재 선택된 단계를 초기화한다.
  void clearSelection() {
    _selected = null;
    notifyListeners();
  }

  /// 저장된 오류 메시지를 초기화한다.
  void clearError() {
    _errorMessage = null;
    notifyListeners();
  }

  bool get hasActiveFilters =>
      _query.trim().isNotEmpty || _statusId != null || _approverId != null;

  /// 검색어/상태/승인자 필터를 기본값으로 리셋한다.
  void resetFilters() {
    _query = '';
    _statusId = null;
    _approverId = null;
    notifyListeners();
  }

  /// 새로운 단계를 생성하고 현재 페이지를 다시 불러온다.
  Future<ApprovalStepRecord?> createStep(ApprovalStepInput input) async {
    _isSaving = true;
    _errorMessage = null;
    notifyListeners();
    try {
      final created = await _repository.create(input);
      final nextPage = _result?.page ?? 1;
      await fetch(page: nextPage);
      return created;
    } catch (error) {
      final failure = Failure.from(error);
      _errorMessage = failure.describe();
      return null;
    } finally {
      _isSaving = false;
      notifyListeners();
    }
  }

  /// 기존 단계를 수정하고 목록을 갱신한다.
  Future<ApprovalStepRecord?> updateStep(
    int id,
    ApprovalStepInput input,
  ) async {
    _isSaving = true;
    _errorMessage = null;
    notifyListeners();
    try {
      final updated = await _repository.update(id, input);
      final nextPage = _result?.page ?? 1;
      await fetch(page: nextPage);
      return updated;
    } catch (error) {
      final failure = Failure.from(error);
      _errorMessage = failure.describe();
      return null;
    } finally {
      _isSaving = false;
      notifyListeners();
    }
  }

  /// 결재 단계를 삭제(비활성화)하고 목록 상태를 반영한다.
  Future<bool> deleteStep(int id) async {
    _isSaving = true;
    _errorMessage = null;
    notifyListeners();
    try {
      await _repository.delete(id);
      if (_result != null) {
        final items = _result!.items
            .map((record) {
              final stepId = record.step.id;
              if (stepId != null && stepId == id) {
                return record.copyWith(
                  step: record.step.copyWith(isDeleted: true),
                );
              }
              return record;
            })
            .toList(growable: false);
        _result = _result!.copyWith(items: items);
      }
      return true;
    } catch (error) {
      final failure = Failure.from(error);
      _errorMessage = failure.describe();
      return false;
    } finally {
      _isSaving = false;
      notifyListeners();
    }
  }

  /// 삭제된 결재 단계를 복구하고 최신 데이터를 반환한다.
  Future<ApprovalStepRecord?> restoreStep(int id) async {
    _isSaving = true;
    _errorMessage = null;
    notifyListeners();
    try {
      final record = await _repository.restore(id);
      if (_result != null) {
        final items = _result!.items
            .map((item) {
              final stepId = item.step.id;
              if (stepId != null && stepId == id) {
                return record;
              }
              return item;
            })
            .toList(growable: false);
        _result = _result!.copyWith(items: items);
      }
      return record;
    } catch (error) {
      final failure = Failure.from(error);
      _errorMessage = failure.describe();
      return null;
    } finally {
      _isSaving = false;
      notifyListeners();
    }
  }
}
