import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:tm_app/data/repositories/tenders_repository.dart';
import 'package:tm_app/data/services/model/feedback_data/feedback_data.dart';
import 'package:tm_app/data/services/model/feedback_response/feedback_response.dart';
import 'package:tm_app/data/services/model/tender_approvals_toggle_data/tender_approvals_toggle_data.dart';
import 'package:tm_app/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.dart';
import 'package:tm_app/data/services/model/tenders/tenders_response/tenders_response.dart';

import '../core/constants/tender_submision_mode.dart';
import '../core/utils/result.dart';
import '../data/services/model/tender_approvals_by_id_response/tender_approvals_by_id_response.dart';
import '../data/services/model/tender_approvals_data/tender_approvals_data.dart';
import 'home_view_model.dart';

class TendersViewModel with ChangeNotifier {
  final TendersRepository _tendersRepository;
  final HomeViewModel _homeViewModel;

  TendersViewModel({
    required TendersRepository tendersRepository,
    required HomeViewModel homeViewModel,
  }) : _tendersRepository = tendersRepository,
       _homeViewModel = homeViewModel {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      getTenders();
    });
  }

  bool _isLoading = false;
  bool _isLoadingMore = false;
  String? _errorMessage;
  String? _feedbackErrorMessage;
  String? _tenderApprovalErrorMessage;
  TendersResponse? _tendersResponse;
  FeedbackData? _feedbackData;
  TenderApprovalsData? _tenderApprovalData;
  TenderApprovalsToggleData? _tenderApprovalToggleData;

  bool get isLoading => _isLoading;
  bool get isLoadingMore => _isLoadingMore;
  String? get errorMessage => _errorMessage;
  String? get feedbackErrorMessage => _feedbackErrorMessage;
  String? get tenderApprovalErrorMessage => _tenderApprovalErrorMessage;
  TendersResponse? get tendersResponse => _tendersResponse;
  FeedbackData? get feedbackData => _feedbackData;
  TenderApprovalsData? get tenderApprovalData => _tenderApprovalData;
  TenderApprovalsToggleData? get tenderApprovalToggleData =>
      _tenderApprovalToggleData;

  List<FeedbackData> feedbacks = [];
  List<TenderApprovalsData> tenderApprovals = [];

  int currentPage = 1;
  int _currentOffset = 0;
  static const int _pageSize = 10;
  bool _hasMoreData = true;

  bool get hasMoreData => _hasMoreData;

  /// Get feedback for a specific tender
  FeedbackData? getFeedbackForTender(String tenderId) {
    try {
      return feedbacks.firstWhere((f) => f.tender == tenderId);
    } catch (e) {
      return null;
    }
  }

  /// Check if feedback exists for a specific tender
  bool hasFeedbackForTender(String tenderId) {
    return feedbacks.any((f) => f.tender == tenderId);
  }

  /// Get tender approval for a specific tender
  TenderApprovalsData? getTenderApprovalForTender(String tenderId) {
    try {
      return tenderApprovals.firstWhere((a) => a.tenderId == tenderId);
    } catch (e) {
      return null;
    }
  }

  /// Check if tender approval exists for a specific tender
  bool hasTenderApprovalForTender(String tenderId) {
    return tenderApprovals.any((a) => a.tenderId == tenderId);
  }

  /// Get approval status for a specific tender
  String? getApprovalStatusForTender(String tenderId) {
    final approval = getTenderApprovalForTender(tenderId);
    return approval?.status;
  }

  Future<void> getTenders() async {
    _isLoading = true;
    notifyListeners();
    clearAll(); // Clear all data before fetching new tenders

    _currentOffset = 0;
    _hasMoreData = true;

    final result = await _tendersRepository.getTenders(
      limit: _pageSize,
      offset: _currentOffset,
    );
    switch (result) {
      case Ok<TendersResponse>():
        _tendersResponse = result.value;
        // Check if we have more data
        if (_tendersResponse?.data?.tenders != null) {
          _hasMoreData = _tendersResponse!.data!.tenders!.length >= _pageSize;
        }
        if (_tendersResponse?.data?.tenders?.isNotEmpty == true) {
          // Fetch feedback and approvals for the first tender only
          getTenderFeedback(_tendersResponse!.data!.tenders!.first.id!);
          getTenderApprovals(_tendersResponse!.data!.tenders!.first.id!);
        }
        break;
      case Error<TendersResponse>():
        _errorMessage = result.error.toString();
        break;
    }
    _isLoading = false;
    notifyListeners();
    _errorMessage = null;
    notifyListeners();
  }

  Future<void> loadMoreTenders() async {
    if (_isLoadingMore || !_hasMoreData) {
      return;
    }

    _isLoadingMore = true;
    _errorMessage = null;
    notifyListeners();

    _currentOffset += _pageSize;
    final result = await _tendersRepository.getTenders(
      limit: _pageSize,
      offset: _currentOffset,
    );

    switch (result) {
      case Ok<TendersResponse>():
        if (result.value.data?.tenders != null &&
            result.value.data!.tenders!.isNotEmpty) {
          // Create a new modifiable list by combining existing and new tenders
          if (_tendersResponse?.data?.tenders != null) {
            final existingTenders = _tendersResponse!.data!.tenders!;
            final newTenders = result.value.data!.tenders!;
            final combinedTenders = [...existingTenders, ...newTenders];

            // Create a new TendersData with the combined list
            _tendersResponse = _tendersResponse!.copyWith(
              data: _tendersResponse!.data!.copyWith(tenders: combinedTenders),
            );
          } else {
            _tendersResponse = result.value;
          }
          // Check if we have more data
          _hasMoreData = result.value.data!.tenders!.length >= _pageSize;
        } else {
          _hasMoreData = false;
        }
        break;
      case Error<TendersResponse>():
        _errorMessage = result.error.toString();
        _currentOffset -= _pageSize; // Revert offset on error
        break;
    }

    _isLoadingMore = false;
    notifyListeners();
    _errorMessage = null;
    notifyListeners();
  }

  Future<void> getTenderFeedback(String tenderId) async {
    // _isLoading = true;
    _errorMessage = null;
    notifyListeners();

    final result = await _tendersRepository.getTenderFeedback(
      tenderId: tenderId,
    );
    switch (result) {
      case Ok<FeedbackResponse>():
        _feedbackData = result.value.data;
        // Add or update _feedbackData in feedbacks list by tender id
        if (_feedbackData != null) {
          final index = feedbacks.indexWhere(
            (f) => f.tender == _feedbackData!.tender,
          );
          if (index != -1) {
            feedbacks[index] = _feedbackData!;
            log('Updated feedback for tender: ${_feedbackData!.tender}');
          } else {
            feedbacks.add(_feedbackData!);
            log('Added new feedback for tender: ${_feedbackData!.tender}');
          }
          log('Total feedbacks: ${feedbacks.length}');
        }
        break;
      case Error<FeedbackResponse>():
        _errorMessage = result.error.toString();
        break;
    }
    // _isLoading = false;
    notifyListeners();
    _errorMessage = null;
    notifyListeners();
  }

  Future<void> getTenderApprovals(String tenderId) async {
    _errorMessage = null;
    notifyListeners();

    final result = await _tendersRepository.getTenderApprovals(
      tenderId: tenderId,
    );
    switch (result) {
      case Ok<TenderApprovalsByIdResponse>():
        _tenderApprovalData = result.value.data;
        // Add or update _tenderApprovalData in tenderApprovals list by tender id
        if (_tenderApprovalData != null) {
          final index = tenderApprovals.indexWhere(
            (a) => a.tenderId == _tenderApprovalData!.tenderId,
          );
          if (index != -1) {
            tenderApprovals[index] = _tenderApprovalData!;
            log(
              'Updated approval for tender: ${_tenderApprovalData!.tenderId}',
            );
          } else {
            tenderApprovals.add(_tenderApprovalData!);
            log(
              'Added new approval for tender: ${_tenderApprovalData!.tenderId}',
            );
          }
          log('Total approvals: ${tenderApprovals.length}');
        }
        break;
      case Error<TenderApprovalsByIdResponse>():
        // Remove the tender from tenderApprovals if an error occurs for this tenderId

        tenderApprovals.removeWhere((a) => a.tenderId == tenderId);
        _errorMessage = result.error.toString();
        break;
    }
    notifyListeners();
    _errorMessage = null;
    notifyListeners();
  }

  Future<void> toogleFeedback({
    required String tenderId,
    required String feedbackType,
  }) async {
    _feedbackErrorMessage = null;

    // Get current feedback for this tender
    final existingFeedback = getFeedbackForTender(tenderId);
    final existingFeedbackIndex = feedbacks.indexWhere(
      (f) => f.tender == tenderId,
    );

    // Create optimistic feedback data
    FeedbackData? optimisticFeedback;

    if (existingFeedback == null) {
      // No existing feedback - create new optimistic feedback
      optimisticFeedback = FeedbackData(
        companyId: null, // Will be filled by server
        createdAt: DateTime.now().millisecondsSinceEpoch,
        customerId: null, // Will be filled by server
        feedbackType: feedbackType,
        id: null, // Will be filled by server
        tender: tenderId,
        updatedAt: DateTime.now().millisecondsSinceEpoch,
      );
      feedbacks.add(optimisticFeedback);
    } else {
      // Existing feedback - update optimistically
      if (existingFeedback.feedbackType == feedbackType) {
        // Same feedback type - remove feedback (toggle off)
        if (existingFeedbackIndex != -1) {
          feedbacks.removeAt(existingFeedbackIndex);
        }
        optimisticFeedback = null;
      } else {
        // Different feedback type - update to new type
        optimisticFeedback = existingFeedback.copyWith(
          feedbackType: feedbackType,
          updatedAt: DateTime.now().millisecondsSinceEpoch,
        );
        if (existingFeedbackIndex != -1) {
          feedbacks[existingFeedbackIndex] = optimisticFeedback;
        }
      }
    }

    // Notify listeners immediately for optimistic update
    notifyListeners();

    // Call API
    final result = await _tendersRepository.toggleFeedback(
      tenderId: tenderId,
      feedbackType: feedbackType,
    );

    switch (result) {
      case Ok<FeedbackResponse>():
        _feedbackData = result.value.data;
        if (_feedbackData != null) {
          // Update with complete data from server
          final index = feedbacks.indexWhere(
            (f) => f.tender == _feedbackData!.tender,
          );
          if (index != -1) {
            feedbacks[index] = _feedbackData!;
          } else {
            feedbacks.add(_feedbackData!);
          }
        } else {
          // Server returned null data - remove feedback
          feedbacks.removeWhere((f) => f.tender == tenderId);
        }
        break;
      case Error<FeedbackResponse>():
        // Revert optimistic update on error
        if (existingFeedback == null) {
          // Remove the optimistic feedback we added
          feedbacks.removeWhere((f) => f.tender == tenderId);
        } else {
          // Restore the original feedback - find current index and update, or add if not found
          final currentIndex = feedbacks.indexWhere(
            (f) => f.tender == tenderId,
          );
          if (currentIndex != -1) {
            feedbacks[currentIndex] = existingFeedback;
          } else {
            feedbacks.add(existingFeedback);
          }
        }
        _feedbackErrorMessage = result.error.toString();
        break;
    }

    notifyListeners();
    _feedbackErrorMessage = null;
    notifyListeners();
  }

  Future<void> toggleApprovals({
    required String tenderId,
    required String submissionMode,
    required String status,
  }) async {
    _tenderApprovalErrorMessage = null;

    // Get current approval for this tender
    final existingApproval = getTenderApprovalForTender(tenderId);
    final existingApprovalIndex = tenderApprovals.indexWhere(
      (a) => a.tenderId == tenderId,
    );

    // Create optimistic approval data
    TenderApprovalsData? optimisticApproval;

    if (existingApproval == null) {
      // No existing approval - create new optimistic approval
      optimisticApproval = TenderApprovalsData(
        id: null, // Will be filled by server
        status: status,
        tenderId: tenderId,
        companyId: null, // Will be filled by server
        submissionMode: submissionMode,
        createdAt: DateTime.now().millisecondsSinceEpoch,
        tender: null,
      );
      tenderApprovals.add(optimisticApproval);
    } else {
      // Existing approval - update optimistically
      if (existingApproval.status == status) {
        // Same status - remove approval (toggle off)
        if (existingApprovalIndex != -1) {
          tenderApprovals.removeAt(existingApprovalIndex);
        }
        optimisticApproval = null;
      } else {
        // Different status - update to new status
        optimisticApproval = existingApproval.copyWith(
          status: status,
          submissionMode: submissionMode,
        );
        if (existingApprovalIndex != -1) {
          tenderApprovals[existingApprovalIndex] = optimisticApproval;
        }
      }
    }

    // Notify listeners immediately for optimistic update
    notifyListeners();

    // Call API
    final result = await _tendersRepository.toggleApprovals(
      tenderId: tenderId,
      submissionMode: submissionMode,
      status: status,
    );

    switch (result) {
      case Ok<TenderApprovalsToggleResponse>():
        _tenderApprovalToggleData = result.value.data;
        if (_tenderApprovalToggleData != null) {
          // Convert TenderApprovalsToggleData to TenderApprovalsData
          final approvalData = TenderApprovalsData(
            id: _tenderApprovalToggleData!.id,
            status: _tenderApprovalToggleData!.status!,
            tenderId: _tenderApprovalToggleData!.tenderId,
            companyId: _tenderApprovalToggleData!.companyId,
            submissionMode:
                (_tenderApprovalToggleData!.submissionMode?.isNotEmpty == true)
                    ? _tenderApprovalToggleData!.submissionMode
                    : TenderSubmissionMode.selfApply.value,
            createdAt: _tenderApprovalToggleData!.createdAt,
            tender: null, // Tender data is not included in toggle response
          );

          final index = tenderApprovals.indexWhere(
            (a) => a.tenderId == approvalData.tenderId,
          );
          if (index != -1) {
            tenderApprovals[index] = approvalData;
          } else {
            tenderApprovals.add(approvalData);
          }
        } else {
          // Server returned null data - remove approval
          tenderApprovals.removeWhere((a) => a.tenderId == tenderId);
        }
        break;
      case Error<TenderApprovalsToggleResponse>():
        // Revert optimistic update on error
        if (existingApproval == null) {
          // Remove the optimistic approval we added
          tenderApprovals.removeWhere((a) => a.tenderId == tenderId);
        } else {
          // Restore the original approval - find current index and update, or add if not found
          final currentIndex = tenderApprovals.indexWhere(
            (a) => a.tenderId == tenderId,
          );
          if (currentIndex != -1) {
            tenderApprovals[currentIndex] = existingApproval;
          } else {
            tenderApprovals.add(existingApproval);
          }
        }
        _tenderApprovalErrorMessage = result.error.toString();
        break;
    }

    notifyListeners();
    _tenderApprovalErrorMessage = null;
    notifyListeners();
  }

  void updateHome() {
    _homeViewModel.init();
  }

  /// Clear all feedbacks
  void clearFeedbacks() {
    feedbacks.clear();
    _feedbackData = null;
    _feedbackErrorMessage = null;
    notifyListeners();
  }

  /// Clear all tenders
  void clearTenders() {
    _tendersResponse = null;
    _errorMessage = null;
    _currentOffset = 0;
    _hasMoreData = true;
    currentPage = 1;
    notifyListeners();
  }

  /// Clear all data (tenders, feedbacks, and approvals)
  void clearAll() {
    clearTenders();
    clearFeedbacks();
    tenderApprovals.clear();
    _tenderApprovalData = null;
    _tenderApprovalToggleData = null;
    _tenderApprovalErrorMessage = null;
    notifyListeners();
  }
}
