import 'dart:async';
import 'dart:math';

import 'package:didvan/models/enums.dart';
import 'package:didvan/models/overview_data.dart';
import 'package:didvan/models/radar_details_data.dart';
import 'package:didvan/models/requests/radar.dart';
import 'package:didvan/providers/core.dart';
import 'package:didvan/services/network/request.dart';
import 'package:didvan/services/network/request_helper.dart';

class RadarDetailsState extends CoreProvier {
  final List<RadarDetailsData?> radars = [];
  late Timer _trackingTimer;
  int _trackingTimerCounter = 0;
  late final int initialIndex;
  late final RadarRequestArgs args;
  String? initialDescription;
  bool isFetchingNewItem = false;
  final List<int> relatedQueue = [];
  bool openComments = false;
  bool _isRequestInProgress = false;

  int _currentIndex = 0;
  int get currentIndex => _currentIndex;

  RadarDetailsData get currentRadar {
    try {
      return radars[_currentIndex]!;
    } catch (e) {
      return radars[_currentIndex + 1]!;
    }
  }

  Future<void> getRadarDetails(int id, {bool? isForward}) async {
    if (_isRequestInProgress) {
      return;
    }
    _isRequestInProgress = true;

    if (isForward == null) {
      appState = AppState.busy;
    } else {
      isFetchingNewItem = true;
      notifyListeners();
    }

    try {
      if (RequestService.token == null || RequestService.token!.isEmpty) {
        await Future.delayed(const Duration(milliseconds: 500));
        if (RequestService.token == null || RequestService.token!.isEmpty) {
          throw Exception('Token not available');
        }
      }

      final service = RequestService(RequestHelper.radarDetails(id, args));
      await service.httpGet();
      _handleTracking(sendRequest: isForward != null);

      if (service.isSuccess) {
        final result = service.result;
        final radar = RadarDetailsData.fromJson(result['radar']);

        if (isForward == null && initialDescription != null) {
          radar.description = initialDescription;
        }

        if (isForward == null && radar.description == null) {
          await _fetchDescriptionFromList(radar.id, radar);
        }

        if (args.page == 0) {
          radars.add(radar);
          initialIndex = 0;
          appState = AppState.idle;
          isFetchingNewItem = false;
          _isRequestInProgress = false;
          return;
        }

        RadarDetailsData? prevRadar;
        if (result['prevRadar'].isNotEmpty) {
          prevRadar = RadarDetailsData.fromJson(result['prevRadar']);
        }

        RadarDetailsData? nextRadar;
        if (result['nextRadar'].isNotEmpty) {
          nextRadar = RadarDetailsData.fromJson(result['nextRadar']);
        }

        if (isForward == null) {
          radars
              .addAll(List.generate(max(radar.order - 2, 0), (index) => null));
          if (prevRadar != null) {
            radars.add(prevRadar);
          }
          radars.add(radar);
          if (nextRadar != null) {
            radars.add(nextRadar);
          }
          _currentIndex = initialIndex = radar.order - 1;
        } else if (isForward) {
          if (!exists(nextRadar) && nextRadar != null) {
            radars.add(nextRadar);
          }
          _currentIndex++;
        } else if (!isForward) {
          if (!exists(prevRadar) && prevRadar != null) {
            radars[_currentIndex - 2] = prevRadar;
          }
          _currentIndex--;
        }
        isFetchingNewItem = false;
        if (currentRadar.contents.length == 1) {
          getRelatedContents();
        }
        appState = AppState.idle;
      } else {
        isFetchingNewItem = false;
        if (isForward == null) {
          appState = AppState.failed;
        } else {
          notifyListeners();
        }
      }
    } catch (e) {
      print('Error fetching radar details: $e');
      isFetchingNewItem = false;
      if (isForward == null) {
        appState = AppState.failed;
      }
      notifyListeners();
    } finally {
      _isRequestInProgress = false;
    }
  }

  Future<void> _fetchDescriptionFromList(
      int radarId, RadarDetailsData radarItem) async {
    try {
      final service = RequestService(
        RequestHelper.radarOverviews(
          args: const RadarRequestArgs(page: 1),
        ),
      );
      await service.httpGet();

      if (service.isSuccess) {
        final radarList = service.result['radars'] as List?;
        if (radarList != null) {
          for (var item in radarList) {
            if (item['id'] == radarId) {
              final radarData = OverviewData.fromJson(item);
              if (radarData.description.isNotEmpty) {
                radarItem.description = radarData.description;
              }
              break;
            }
          }
        }
      }
    } catch (e) {
      // ignore: avoid_print
      print('Error fetching description from list: $e');
    }
  }

  Future<void> getRelatedContents() async {
    if (currentRadar.relatedContents.isNotEmpty &&
        currentRadar.relatedContentsIsEmpty) {
      return;
    }
    relatedQueue.add(currentRadar.id);
    final service = RequestService(RequestHelper.tag(
      ids: currentRadar.tags.map((tag) => tag.id).toList(),
      itemId: currentRadar.id,
      type: 'radar',
    ));
    await service.httpGet();
    if (service.isSuccess) {
      final relateds = service.result['contents'];
      for (var i = 0; i < relateds.length; i++) {
        radars
            .where((element) => element != null)
            .firstWhere((element) => element!.id == currentRadar.id)!
            .relatedContents
            .add(OverviewData.fromJson(relateds[i]));
      }
      if (relateds.isEmpty) {
        radars
            .where((element) => element != null)
            .firstWhere((element) => element!.id == currentRadar.id)
            ?.relatedContentsIsEmpty = true;
      }
    } else {
      radars
          .where((element) => element != null)
          .firstWhere((element) => element!.id == currentRadar.id)
          ?.relatedContentsIsEmpty = true;
    }
    notifyListeners();
  }

  bool exists(RadarDetailsData? radar) =>
      radars.any((r) => radar != null && r != null && r.id == radar.id);

  void onCommentsChanged(int count) {
    radars.firstWhere((radar) => radar?.id == currentRadar.id)!.comments =
        count;
    notifyListeners();
  }

  Future<void> _handleTracking({bool sendRequest = true}) async {
    if (!sendRequest) {
      _trackingTimerCounter = 0;
      _trackingTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
        _trackingTimerCounter++;
      });
      return;
    }
    final service = RequestService(
      RequestHelper.tracking(currentRadar.id, 'radar'),
      body: {
        'sec': _trackingTimerCounter,
      },
    );
    service.put();
    _trackingTimerCounter = 0;
    _trackingTimer.cancel();
  }

  @override
  void dispose() {
    _handleTracking(sendRequest: true);
    _trackingTimer.cancel();
    super.dispose();
  }
}
