import 'dart:convert';
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:electronic_assistant/data/api/atmob_api.dart';
import 'package:electronic_assistant/data/api/atmob_file_api.dart';
import 'package:electronic_assistant/data/api/atmob_stream_api.dart';
import 'package:electronic_assistant/data/api/request/talk_create_request.dart';
import 'package:electronic_assistant/data/api/request/talk_delete_request.dart';
import 'package:electronic_assistant/data/api/request/talk_file_request.dart';
import 'package:electronic_assistant/data/api/request/talk_translate_request.dart';
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
import 'package:get/get.dart';
import 'package:get/get_connect/http/src/request/request.dart';
import 'package:path_provider/path_provider.dart';
import '../../base/base_response.dart';
import '../../dialog/talk_share_dialog.dart';
import '../../utils/foreground_util.dart';
import '../../utils/http_handler.dart';
import '../api/request/talk_export_request.dart';
import '../api/request/talk_generate_request.dart';
import '../api/request/talk_paginate_request.dart';
import '../api/request/talk_rename_request.dart';
import '../api/request/talk_request.dart';
import '../api/request/talk_summary_generate_request.dart';
import '../api/response/talk_check_electric_response.dart';
import '../api/response/talk_info_response.dart';
import '../api/response/talk_paginate_response.dart';
import '../api/response/talk_translate_response.dart';
import '../bean/talk_original.dart';
import '../bean/talks.dart';
import 'account_repository.dart';

class TalkRepository {
  TalkRepository._();

  final Set<String> _uploadingTalkIds = {};

  final Map<String, RxDouble> _uploadingTalkProgress = {};

  final _talkList = RxList<TalkBean>();

  RxList<TalkBean> get talkList => _talkList;

  Future<TalkBean> talkSummaryGenerate(String id, int templateId) {
    return atmobApi
        .talkSummaryGenerate(TalkSummaryGenerateRequest(id, templateId))
        .then(HttpHandler.handle(false));
  }

  Future<TalkTranslateResponse> talkTranslate(String content) {
    return atmobApi
        .talkTranslate(TalkTranslateRequest(content))
        .then(HttpHandler.handle(false));
  }

  bool isUploadingTalk(String talkId) {
    return _uploadingTalkIds.contains(talkId);
  }

  void renovateTalkData(TalkBean talkInfo) {
    for (int i = 0; i < _talkList.length; i++) {
      if (_talkList[i].id == talkInfo.id) {
        _talkList[i].updateBean(talkInfo);
        break;
      }
    }
  }

  Future<File> talkExport(
      String talkId, String fileName, ShareTalkType type) async {
    ResponseBody responseBody = await atmobStreamApi.talkExportFile(
        TalkExportRequest(talkId, type == ShareTalkType.summary ? 1 : 2));
    List<String>? contentType = responseBody.headers['Content-Type'];

    if (contentType != null) {
      for (var value in contentType) {
        if (value.contains('application/json')) {
          BaseResponse<String> baseResponse = BaseResponse.fromJson(
              jsonDecode(await responseBody.stream
                  .map((bytes) => utf8.decoder.convert(bytes))
                  .toList()
                  .then((value) => value.join())),
              (json) => json as String);
          throw ServerErrorException(baseResponse.code, baseResponse.message);
        } else {
          final directory = await getTemporaryDirectory();
          final filePath = '${directory.path}/export/$fileName';

          final file = File(filePath);

          if (!await file.exists()) {
            await file.create(recursive: true);
          }

          await file.writeAsBytes(await responseBody.stream.toBytes());
          return file;
        }
      }
    }
    throw Exception('Invalid content type');
  }

  void setTalkList(List<TalkBean> list) {
    _talkList.assignAll(list);
  }

  void addNewTalkData(TalkBean talkInfo) {
    _talkList.insert(0, talkInfo);
  }

  clearTalkList() {
    _talkList.clear();
  }

  Future<TalkPaginateResponse> refreshHomeTalkData({int? sortType = 1}) {
    int limit;
    if (_talkList.isEmpty || _talkList.length < 10) {
      limit = 10;
    } else {
      limit = _talkList.length;
    }
    return requestTalkPagePaginate(0, limit,
        sortType: sortType, isClearAll: true);
  }

  Future<TalkPaginateResponse> requestTalkPagePaginate(int offset, int limit,
      {String? searchKeyword, int? sortType = 1, bool? isClearAll = false}) {
    return talkPagePaginate(offset, limit,
            searchKeyword: searchKeyword, sortType: sortType)
        .then((response) {
      if (isClearAll == true) {
        _talkList.clear();
      }
      if (response.list != null) {
        _talkList.addAll(response.list!);
      }
      return response;
    });
  }

  ///sortType 1：按创建时间倒序 2：按更新时间倒序
  Future<TalkPaginateResponse> talkPagePaginate(int offset, int limit,
      {String? searchKeyword, int? sortType = 1}) {
    return atmobApi
        .talkPagePaginate(TalkPaginateRequest(offset, limit,
            searchKeyword: searchKeyword, sortType: sortType))
        .then(HttpHandler.handle(false));
  }

  Future<List<TalkOriginal>> talkOriginal(String? talkId) {
    return atmobApi
        .talkOriginal(
            TalkRequest(talkId, isExample: !accountRepository.isLogin.value))
        .then(HttpHandler.handle(false))
        .then((data) {
      if (data.list != null) {
        return data.list!;
      } else {
        return [];
      }
    });
  }

  // duration 音频时长，单位为秒
  Future<TalkCheckElectricResponse> checkElectric(double duration) {
    return atmobApi
        .checkElectric(TalkGenerateRequest(duration))
        .then(HttpHandler.handle(false));
  }

  Future<TalkInfoResponse> talkInfo(String id) {
    return atmobApi
        .talkInfo(TalkRequest(id, isExample: !accountRepository.isLogin.value))
        .then(HttpHandler.handle(true));
  }

  Future<void> talkRename(String? id, String? title) {
    return atmobApi
        .talkRename(TalkRenameRequest(id, title))
        .then(HttpHandler.handle(true));
  }

  Future<void> talkDelete(String? id) {
    return atmobApi
        .talkDelete(TalkDeleteRequest(id))
        .then(HttpHandler.handle(true));
  }

  Future<TalkBean> talkCreate(String requestId, int duration,
      {String? localAudioUrl, FileUploadType? uploadType}) {
    return atmobApi
        .talkCreate(TalkCreateRequest(duration, requestId,
            localAudioUrl: localAudioUrl, uploadType: uploadType?.value))
        .then(HttpHandler.handle(true))
        .then((bean) {
      //添加新的录音到最新记录
      talkRepository.addNewTalkData(bean);
      return bean;
    });
  }

  Future<String> uploadTalkFile(String talkId, double duration, File file) {
    _uploadingTalkIds.add(talkId);
    startForegroundService(
        serviceId: talkId.hashCode,
        notificationTitle: '正在上传录音',
        notificationText: '请勿关闭应用',
        callback: setUploadCallback);
    RxDouble progressRx = getUploadProgress(talkId);
    return atmobFileApi
        .uploadTalkFile(TalkFileRequest(talkId, duration, file: file).toJson(),
            onSendProgress: (count, total) {
          progressRx.value = count / total;
        })
        .then(HttpHandler.handle(true))
        .then((response) {
          _uploadingTalkIds.remove(talkId);
          return response.taskId;
        })
        .catchError((error) {
          _uploadingTalkIds.remove(talkId);
          throw error;
        })
        .whenComplete(() {
          stopForegroundService();
        });
  }

  RxDouble getUploadProgress(String talkId) {
    if (_uploadingTalkProgress[talkId] == null) {
      _uploadingTalkProgress[talkId] = RxDouble(0);
    }
    return _uploadingTalkProgress[talkId]!;
  }
}

class UploadTaskHandler extends TaskHandler {
  @override
  Future<void> onDestroy(DateTime timestamp) {
    // TODO: implement onDestroy
    return Future.value();
  }

  @override
  void onRepeatEvent(DateTime timestamp) {
    // TODO: implement onRepeatEvent
  }

  @override
  Future<void> onStart(DateTime timestamp, TaskStarter starter) {
    // TODO: implement onStart
    return Future.value();
  }
}

@pragma('vm:entry-point')
void setUploadCallback() {
  // The setTaskHandler function must be called to handle the task in the background.
  FlutterForegroundTask.setTaskHandler(UploadTaskHandler());
}

enum FileUploadType {
  record(0),
  local(1);

  final int value;

  const FileUploadType(this.value);
}

final talkRepository = TalkRepository._();
