// ignore_for_file: avoid_init_to_null

import 'dart:async';

import 'package:color/color.dart';
import 'package:dart_framework/utils/system_util.dart';
import 'package:oto/oto/commands/command.dart';
import 'package:oto/oto/data/command_data.dart';
import 'package:oto/oto/utils/mattermost/mattermost_data.dart';
import 'package:oto/oto/utils/mattermost/mattermost_sender.dart';

class Mattermost extends Command {
  @override
  Future execute(DataCommand command) async {
    final data = DataMattermostSender.fromJson(getParam(command));
    final sender = MattermostSender(data.token, data.url);

    if (data.property != null) {
      final value = data.property;
      if (value is DataMattermost) {
        await sender.sendData(value, defaultChannelId: data.channelId);
      } else if (value is Map) {
        await sender.sendMap(
          DataMattermost.fromJson(Map<String, dynamic>.from(value))
              .toPostJson(defaultChannelId: data.channelId),
        );
      } else {
        throw Exception('The property must be DataMattermost or Map.');
      }
    } else if (data.message != null) {
      final payload = Map<String, dynamic>.from(data.message!);
      await sender.sendMap(
          _replaceMentionsInMap(payload, data.idMap).cast<String, dynamic>());
    } else if (data.messageJson != null) {
      await sender.send(getName2ID(data.messageJson!, data.idMap));
    } else {
      throw Exception('property or message field should not be null');
    }

    return simpleFuture;
  }

  String getName2ID(String message, Map<String, String>? idMap) {
    if (idMap == null) {
      return message;
    }

    for (final entry in idMap.entries) {
      message = message.replaceAll('@${entry.key}', '@${entry.value}');
    }
    return message;
  }

  dynamic _replaceMentionsInMap(dynamic value, Map<String, String>? idMap) {
    if (idMap == null) {
      return value;
    }
    if (value is String) {
      var replaced = value;
      for (final entry in idMap.entries) {
        replaced = replaced.replaceAll('@${entry.key}', '@${entry.value}');
      }
      return replaced;
    }
    if (value is List) {
      return value.map((item) => _replaceMentionsInMap(item, idMap)).toList();
    }
    if (value is Map) {
      return value.map(
          (key, item) => MapEntry(key, _replaceMentionsInMap(item, idMap)));
    }
    return value;
  }
}

class MattermostBuild extends Command {
  @override
  Future execute(DataCommand command) async {
    final data = DataMattermostBuild.fromJson(getParam(command));
    final sender = MattermostSender(data.token, data.url);
    final channelId = data.channelId;
    if (channelId == null || channelId.isEmpty) {
      throw Exception('channelId is required for MattermostBuild.');
    }

    await sender.sendBuild(
      data.appName,
      data.type,
      Color.hex(data.color),
      data.version,
      data.downloadURL,
      channelId: channelId,
    );

    return complete(0, command);
  }
}

void registerMattermostCommands() {
  Command.register(
    CommandType.Mattermost,
    () => Mattermost(),
    spec: const CommandSpec(
      type: CommandType.Mattermost,
      category: 'notification',
      dataModel: 'DataMattermostSender',
      samplePath: 'assets/yaml/sample/08_notification.yaml',
    ),
  );
  Command.register(
    CommandType.MattermostBuild,
    () => MattermostBuild(),
    spec: const CommandSpec(
      type: CommandType.MattermostBuild,
      category: 'notification',
      dataModel: 'DataMattermostBuild',
      samplePath: 'assets/yaml/sample/08_notification.yaml',
    ),
  );
}
