part of 'api_service.dart';

extension ApiServiceMedia on ApiService {
  void updateProfileText(
    String firstName,
    String lastName,
    String description,
  ) {
    final payload = {
      "firstName": firstName,
      "lastName": lastName,
      "description": description,
    };
    _sendMessage(16, payload);
  }

  Future<void> updateProfilePhoto(String firstName, String lastName) async {
    try {
      final picker = ImagePicker();
      final XFile? image = await picker.pickImage(source: ImageSource.gallery);
      if (image == null) return;

      print("Запрашиваем URL для загрузки фото...");
      final int seq = _sendMessage(80, {"count": 1});
      final response = await messages.firstWhere((msg) => msg['seq'] == seq);
      final String uploadUrl = response['payload']['url'];
      print("URL получен: $uploadUrl");

      print("Загружаем фото на сервер...");
      var request = http.MultipartRequest('POST', Uri.parse(uploadUrl));
      request.files.add(await http.MultipartFile.fromPath('file', image.path));
      var streamedResponse = await request.send();
      var httpResponse = await http.Response.fromStream(streamedResponse);

      if (httpResponse.statusCode != 200) {
        throw Exception("Ошибка загрузки фото: ${httpResponse.body}");
      }

      final uploadResult = jsonDecode(httpResponse.body);
      final String photoToken = uploadResult['photos'].values.first['token'];
      print("Фото загружено, получен токен: $photoToken");

      print("Привязываем фото к профилю...");
      final payload = {
        "firstName": firstName,
        "lastName": lastName,
        "photoToken": photoToken,
        "avatarType": "USER_AVATAR",
      };
      _sendMessage(16, payload);
      print("Запрос на смену аватара отправлен.");
    } catch (e) {
      print("!!! Ошибка в процессе смены аватара: $e");
    }
  }

  Future<void> sendPhotoMessage(
    int chatId, {
    String? localPath,
    String? caption,
    int? cidOverride,
    int? senderId,
  }) async {
    try {
      XFile? image;
      if (localPath != null) {
        image = XFile(localPath);
      } else {
        final picker = ImagePicker();
        image = await picker.pickImage(source: ImageSource.gallery);
        if (image == null) return;
      }

      await waitUntilOnline();

      final int seq80 = _sendMessage(80, {"count": 1});
      final resp80 = await messages.firstWhere((m) => m['seq'] == seq80);
      final String uploadUrl = resp80['payload']['url'];

      var request = http.MultipartRequest('POST', Uri.parse(uploadUrl));
      request.files.add(await http.MultipartFile.fromPath('file', image.path));
      var streamed = await request.send();
      var httpResp = await http.Response.fromStream(streamed);
      if (httpResp.statusCode != 200) {
        throw Exception(
          'Ошибка загрузки фото: ${httpResp.statusCode} ${httpResp.body}',
        );
      }
      final uploadJson = jsonDecode(httpResp.body) as Map<String, dynamic>;
      final Map photos = uploadJson['photos'] as Map;
      if (photos.isEmpty) throw Exception('Не получен токен фото');
      final String photoToken = (photos.values.first as Map)['token'];

      final int cid = cidOverride ?? DateTime.now().millisecondsSinceEpoch;
      final payload = {
        "chatId": chatId,
        "message": {
          "text": caption?.trim() ?? "",
          "cid": cid,
          "elements": [],
          "attaches": [
            {"_type": "PHOTO", "photoToken": photoToken},
          ],
        },
        "notify": true,
      };

      clearChatsCache();

      if (localPath != null) {
        _emitLocal({
          'ver': 11,
          'cmd': 1,
          'seq': -1,
          'opcode': 128,
          'payload': {
            'chatId': chatId,
            'message': {
              'id': 'local_$cid',
              'sender': senderId ?? 0,
              'time': DateTime.now().millisecondsSinceEpoch,
              'text': caption?.trim() ?? '',
              'type': 'USER',
              'cid': cid,
              'attaches': [
                {'_type': 'PHOTO', 'url': 'file://$localPath'},
              ],
            },
          },
        });
      }

      _sendMessage(64, payload);
    } catch (e) {
      print('Ошибка отправки фото-сообщения: $e');
    }
  }

  Future<void> sendPhotoMessages(
    int chatId, {
    required List<String> localPaths,
    String? caption,
    int? senderId,
  }) async {
    if (localPaths.isEmpty) return;
    try {
      await waitUntilOnline();

      final int cid = DateTime.now().millisecondsSinceEpoch;
      _emitLocal({
        'ver': 11,
        'cmd': 1,
        'seq': -1,
        'opcode': 128,
        'payload': {
          'chatId': chatId,
          'message': {
            'id': 'local_$cid',
            'sender': senderId ?? 0,
            'time': DateTime.now().millisecondsSinceEpoch,
            'text': caption?.trim() ?? '',
            'type': 'USER',
            'cid': cid,
            'attaches': [
              for (final p in localPaths)
                {'_type': 'PHOTO', 'url': 'file://$p'},
            ],
          },
        },
      });

      final List<Map<String, String>> photoTokens = [];
      for (final path in localPaths) {
        final int seq80 = _sendMessage(80, {"count": 1});
        final resp80 = await messages.firstWhere((m) => m['seq'] == seq80);
        final String uploadUrl = resp80['payload']['url'];

        var request = http.MultipartRequest('POST', Uri.parse(uploadUrl));
        request.files.add(await http.MultipartFile.fromPath('file', path));
        var streamed = await request.send();
        var httpResp = await http.Response.fromStream(streamed);
        if (httpResp.statusCode != 200) {
          throw Exception(
            'Ошибка загрузки фото: ${httpResp.statusCode} ${httpResp.body}',
          );
        }
        final uploadJson = jsonDecode(httpResp.body) as Map<String, dynamic>;
        final Map photos = uploadJson['photos'] as Map;
        if (photos.isEmpty) throw Exception('Не получен токен фото');
        final String photoToken = (photos.values.first as Map)['token'];
        photoTokens.add({"token": photoToken});
      }

      final payload = {
        "chatId": chatId,
        "message": {
          "text": caption?.trim() ?? "",
          "cid": cid,
          "elements": [],
          "attaches": [
            for (final t in photoTokens)
              {"_type": "PHOTO", "photoToken": t["token"]},
          ],
        },
        "notify": true,
      };

      clearChatsCache();
      _sendMessage(64, payload);
    } catch (e) {
      print('Ошибка отправки фото-сообщений: $e');
    }
  }

  Future<void> sendFileMessage(
    int chatId, {
    String? caption,
    int? senderId,
  }) async {
    try {
      FilePickerResult? result = await FilePicker.platform.pickFiles(
        type: FileType.any,
      );

      if (result == null || result.files.single.path == null) {
        print("Выбор файла отменен");
        return;
      }

      final String filePath = result.files.single.path!;
      final String fileName = result.files.single.name;
      final int fileSize = result.files.single.size;

      await waitUntilOnline();

      final int seq87 = _sendMessage(87, {"count": 1});
      final resp87 = await messages.firstWhere((m) => m['seq'] == seq87);

      if (resp87['payload'] == null ||
          resp87['payload']['info'] == null ||
          (resp87['payload']['info'] as List).isEmpty) {
        throw Exception('Неверный ответ на Opcode 87: отсутствует "info"');
      }

      final uploadInfo = (resp87['payload']['info'] as List).first;
      final String uploadUrl = uploadInfo['url'];
      final int fileId = uploadInfo['fileId'];

      print('Получен fileId: $fileId и URL: $uploadUrl');

      var request = http.MultipartRequest('POST', Uri.parse(uploadUrl));
      request.files.add(await http.MultipartFile.fromPath('file', filePath));
      var streamed = await request.send();
      var httpResp = await http.Response.fromStream(streamed);
      if (httpResp.statusCode != 200) {
        throw Exception(
          'Ошибка загрузки файла: ${httpResp.statusCode} ${httpResp.body}',
        );
      }

      print('Файл успешно загружен на сервер.');

      final int cid = DateTime.now().millisecondsSinceEpoch;
      final payload = {
        "chatId": chatId,
        "message": {
          "text": caption?.trim() ?? "",
          "cid": cid,
          "elements": [],
          "attaches": [
            {"_type": "FILE", "fileId": fileId},
          ],
        },
        "notify": true,
      };

      clearChatsCache();

      _emitLocal({
        'ver': 11,
        'cmd': 1,
        'seq': -1,
        'opcode': 128,
        'payload': {
          'chatId': chatId,
          'message': {
            'id': 'local_$cid',
            'sender': senderId ?? 0,
            'time': DateTime.now().millisecondsSinceEpoch,
            'text': caption?.trim() ?? '',
            'type': 'USER',
            'cid': cid,
            'attaches': [
              {
                '_type': 'FILE',
                'name': fileName,
                'size': fileSize,
                'url': 'file://$filePath',
              },
            ],
          },
        },
      });

      _sendMessage(64, payload);
      print('Сообщение о файле (Opcode 64) отправлено.');
    } catch (e) {
      print('Ошибка отправки файла: $e');
    }
  }

  Future<String> getVideoUrl(int videoId, int chatId, String messageId) async {
    await waitUntilOnline();

    final payload = {
      "videoId": videoId,
      "chatId": chatId,
      "messageId": messageId,
    };

    final int seq = _sendMessage(83, payload);
    print('Запрашиваем URL для videoId: $videoId (seq: $seq)');

    try {
      final response = await messages
          .firstWhere((msg) => msg['seq'] == seq && msg['opcode'] == 83)
          .timeout(const Duration(seconds: 15));

      if (response['cmd'] == 3) {
        throw Exception(
          'Ошибка получения URL видео: ${response['payload']?['message']}',
        );
      }

      final videoPayload = response['payload'] as Map<String, dynamic>?;
      if (videoPayload == null) {
        throw Exception('Получен пустой payload для видео');
      }

      String? videoUrl =
          videoPayload['MP4_720'] as String? ??
          videoPayload['MP4_480'] as String? ??
          videoPayload['MP4_1080'] as String? ??
          videoPayload['MP4_360'] as String?;

      if (videoUrl == null) {
        final mp4Key = videoPayload.keys.firstWhere(
          (k) => k.startsWith('MP4_'),
          orElse: () => '',
        );
        if (mp4Key.isNotEmpty) {
          videoUrl = videoPayload[mp4Key] as String?;
        }
      }

      if (videoUrl != null) {
        print('URL для videoId: $videoId успешно получен.');
        return videoUrl;
      } else {
        throw Exception('Не найден ни один MP4 URL в ответе');
      }
    } on TimeoutException {
      print('Таймаут ожидания URL для videoId: $videoId');
      throw Exception('Сервер не ответил на запрос видео вовремя');
    } catch (e) {
      print('Ошибка в getVideoUrl: $e');
      rethrow;
    }
  }
}

