import 'package:flutter/material.dart';
import 'package:tm_app/core/utils/result.dart';
import 'package:tm_app/data/repositories/liked_tenders_repository.dart';
import 'package:tm_app/data/repositories/tenders_repository.dart';
import 'package:tm_app/data/services/model/liked_tender_feedback/liked_tender_feedback.dart';
import 'package:tm_app/data/services/model/liked_tenders_response/liked_tenders_response.dart';
import 'package:tm_app/data/services/model/tender_approvals_toggle_response/tender_approvals_toggle_response.dart';
import 'package:tm_app/view_models/home_view_model.dart';

import '../core/constants/tender_approval_status.dart';
import '../data/services/model/feedback_response/feedback_response.dart';
import '../data/services/model/request_models/tender_feedback_request_model/tender_feedback_request_model.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';

class LikedTendersViewModel with ChangeNotifier {
  final LikedTendersRepository _likedTendersRepository;
  final TendersRepository _tendersRepository;
  final HomeViewModel _homeViewModel;
  LikedTendersViewModel({
    required LikedTendersRepository likedTendersRepository,
    required TendersRepository tendersRepository,
    required HomeViewModel homeViewModel,
  }) : _likedTendersRepository = likedTendersRepository,
       _homeViewModel = homeViewModel,
       _tendersRepository = tendersRepository;

  bool isLoading = false;
  bool isLoadingMore = false;
  bool hasMore = true;
  String? errorMessage;
  LikedTendersResponse? data;
  TenderApprovalsData? _tenderApprovalData;

  TenderApprovalsData? get tenderApprovalData => _tenderApprovalData;

  List<TenderApprovalsData> tenderApprovals = [];

  int _offset = 0;
  final int _limit = 7;

  int currentPage = 1;

  // Approval status properties
  bool approvalStatus = false;
  String _status = '';
  String? _errorMessage;
  bool _isSubmitApprovalLoading = false;
  bool _isRejectApprovalLoading = false;

  String get status => _status;
  String? get approvalErrorMessage => _errorMessage;
  bool get isSubmitApprovalLoading => _isSubmitApprovalLoading;
  bool get isRejectApprovalLoading => _isRejectApprovalLoading;

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

  void clearApprovalErrorMessage() {
    _errorMessage = null;
    notifyListeners();
  }

  Future<void> getLikedTenders({bool reset = false}) async {
    if (!reset && (isLoadingMore || !hasMore)) {
      return;
    }

    if (reset) {
      _offset = (currentPage - 1) * _limit;
      hasMore = true;

      data = null;
      isLoading = true;
      notifyListeners();
    } else {
      if (_offset == 0) {
        isLoading = true;
      } else {
        isLoadingMore = true;
      }
      notifyListeners();
    }

    errorMessage = null;

    final requestModel = TenderFeedbackRequestModel(
      offset: _offset,
      limit: _limit,
      feedbackType: 'like',
    );

    final result = await _likedTendersRepository.getLikedTenders(
      requestModel: requestModel,
    );

    switch (result) {
      case Ok<LikedTendersResponse>():
        final incoming = result.value;
        final incomingList = incoming.data?.feedback ?? [];

        for (var element in incomingList) {
          await getTenderApproval(element.tenderId!);
        }

        if (reset) {
          data = incoming;
        } else {
          final existingList = data?.data?.feedback ?? [];
          final combined = List<LikedTenderFeedback>.of(existingList)
            ..addAll(incomingList);

          data = data?.copyWith(
            data: data?.data?.copyWith(
              feedback: combined,
              meta: incoming.data?.meta ?? data!.data!.meta,
            ),
          );
        }

        hasMore = incomingList.length == _limit;
        _offset += _limit;

        errorMessage = null;
        break;

      case Error<LikedTendersResponse>():
        errorMessage = result.error.toString();
        break;
    }

    isLoading = false;
    isLoadingMore = false;
    notifyListeners();
  }

  Future<void> loadMoreIfNeeded() async {
    if (isLoadingMore || !hasMore) {
      return;
    }
    await getLikedTenders(reset: false);
  }

  Future<void> jumpToPage(int page) async {
    currentPage = page;
    _offset = (page - 1) * _limit;
    hasMore = true;
    await getLikedTenders(reset: true);
  }

  void removeTenderById(String id) async {
    final current = data;
    final list = current?.data?.feedback;
    if (current == null || list == null) {
      return;
    }

    // Store original list to restore if error occurs
    final originalList = List<LikedTenderFeedback>.of(list);
    final updatedList = List<LikedTenderFeedback>.of(list)
      ..removeWhere((e) => e.tenderId == id);

    // Temporarily update UI
    data = current.copyWith(
      data: current.data?.copyWith(feedback: updatedList),
    );
    notifyListeners();

    final result = await _tendersRepository.toggleFeedback(
      tenderId: id,
      feedbackType: 'like',
    );

    switch (result) {
      case Ok<FeedbackResponse>():
        final updatedMeta = current.data?.meta?.copyWith(
          total: updatedList.length,
        );
        data = current.copyWith(
          data: current.data?.copyWith(
            feedback: updatedList,
            meta: updatedMeta,
          ),
        );
        break;
      case Error<FeedbackResponse>():
        // Restore original list if error occurs
        data = current.copyWith(
          data: current.data?.copyWith(feedback: originalList),
        );
        errorMessage = result.error.toString();
        break;
    }

    notifyListeners();
  }

  Future<void> getTenderApproval(String tenderId) async {
    errorMessage = null;
    notifyListeners();

    final result = await _tendersRepository.getTenderApprovals(
      tenderId: tenderId,
    );

    switch (result) {
      case Ok<TenderApprovalsByIdResponse>():
        _tenderApprovalData = result.value.data;
        tenderApprovals.add(_tenderApprovalData!);
        break;
      case Error<TenderApprovalsByIdResponse>():
        errorMessage = result.error.toString();
        break;
    }

    notifyListeners();
    errorMessage = null;
    notifyListeners();
  }

  TenderApprovalsData? getApprovalStatusForTender(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 tender safely
  String? getApprovalStatusForTenderId(String tenderId) {
    try {
      final approval = tenderApprovals.firstWhere(
        (a) => a.tenderId == tenderId,
      );
      return approval.status;
    } catch (e) {
      return null;
    }
  }

  /// Check if tender is submitted
  bool isTenderSubmitted(String tenderId) {
    return getApprovalStatusForTenderId(tenderId) ==
        TenderApprovalStatus.submitted.value;
  }

  /// Check if tender is rejected
  bool isTenderRejected(String tenderId) {
    return getApprovalStatusForTenderId(tenderId) ==
        TenderApprovalStatus.rejected.value;
  }

  Future<void> submitTenderApproval({
    required String tenderId,
    required String submissionMode,
  }) async {
    _isSubmitApprovalLoading = true;
    _errorMessage = null;
    notifyListeners();

    // Store original state for rollback
    final originalApprovals = List<TenderApprovalsData>.of(tenderApprovals);

    // Check current approval status and update optimistically
    final existingApproval = getApprovalStatusForTender(tenderId);

    if (existingApproval != null) {
      if (existingApproval.status == TenderApprovalStatus.submitted.value) {
        // Remove from list if already submitted
        tenderApprovals.removeWhere((a) => a.tenderId == tenderId);
      } else if (existingApproval.status ==
          TenderApprovalStatus.rejected.value) {
        // Change rejected to submitted
        final updatedApproval = existingApproval.copyWith(
          status: TenderApprovalStatus.submitted.value,
        );
        final index = tenderApprovals.indexWhere((a) => a.tenderId == tenderId);
        if (index != -1) {
          tenderApprovals[index] = updatedApproval;
        }
      }
    } else {
      // Add new approval with submitted status
      final newApproval = TenderApprovalsData(
        id: null,
        status: TenderApprovalStatus.submitted.value,
        tenderId: tenderId,
        companyId: null,
        submissionMode: submissionMode,
        createdAt: null,
        tender: null,
      );
      tenderApprovals.add(newApproval);
    }

    notifyListeners();

    // Make server request
    final result = await _tendersRepository.toggleApprovals(
      tenderId: tenderId,
      status: TenderApprovalStatus.submitted.value,
      submissionMode: submissionMode,
    );

    switch (result) {
      case Ok<TenderApprovalsToggleResponse>():
        approvalStatus = true;
        _status = result.value.data?.status ?? '';
        break;
      case Error<TenderApprovalsToggleResponse>():
        // Rollback changes on error
        tenderApprovals = originalApprovals;
        _errorMessage = result.error.toString();
        approvalStatus = false;
        break;
    }
    approvalStatus = false;
    _isSubmitApprovalLoading = false;
    notifyListeners();
  }

  Future<void> rejectTenderApproval({
    required String tenderId,
    required String submissionMode,
  }) async {
    _isRejectApprovalLoading = true;
    _errorMessage = null;
    notifyListeners();

    // Store original state for rollback
    final originalApprovals = List<TenderApprovalsData>.of(tenderApprovals);

    // Check current approval status and update optimistically
    final existingApproval = getApprovalStatusForTender(tenderId);

    if (existingApproval != null) {
      if (existingApproval.status == TenderApprovalStatus.rejected.value) {
        // Remove from list if already rejected
        tenderApprovals.removeWhere((a) => a.tenderId == tenderId);
      } else if (existingApproval.status ==
          TenderApprovalStatus.submitted.value) {
        // Change submitted to rejected
        final updatedApproval = existingApproval.copyWith(
          status: TenderApprovalStatus.rejected.value,
        );
        final index = tenderApprovals.indexWhere((a) => a.tenderId == tenderId);
        if (index != -1) {
          tenderApprovals[index] = updatedApproval;
        }
      }
    } else {
      // Add new approval with rejected status
      final newApproval = TenderApprovalsData(
        id: null,
        status: TenderApprovalStatus.rejected.value,
        tenderId: tenderId,
        companyId: null,
        submissionMode: submissionMode,
        createdAt: null,
        tender: null,
      );
      tenderApprovals.add(newApproval);
    }

    notifyListeners();

    // Make server request
    final result = await _tendersRepository.toggleApprovals(
      tenderId: tenderId,
      status: TenderApprovalStatus.rejected.value,
      submissionMode: submissionMode,
    );

    switch (result) {
      case Ok<TenderApprovalsToggleResponse>():
        approvalStatus = true;
        _status = result.value.data?.status ?? '';
        break;
      case Error<TenderApprovalsToggleResponse>():
        // Rollback changes on error
        tenderApprovals = originalApprovals;
        _errorMessage = result.error.toString();
        approvalStatus = false;
        break;
    }

    approvalStatus = false;
    _isRejectApprovalLoading = false;
    notifyListeners();
  }
}
