// ignore_for_file: avoid_init_to_null

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

import 'package:dart_framework/utils/slack/slack_data.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:color/color.dart';
import 'package:dart_framework/utils/slack/slack_sender.dart';
import 'package:dart_framework/utils/slack/slack_data.dart' as slack_data;

class Slack extends Command {
  @override
  Future execute(DataCommand command) async {
    var data = DataSlackSender.fromJson(getParam(command));
    var sender = SlackSender(data.token);
    if (data.property != null) {
      var value = data.property as DataSlack?;
      if (value != null) {
        await sender.sendData(value); 
      } else {
        throw Exception('The property is null.');
      }
    } else if(data.message != null) {
      await sender.send(jsonEncode(data.message));
    } 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;
    } else {
      for(var entry in idMap.entries) {
        message = message.replaceAll('@${entry.key}', '<@${entry.value}>');
      }
      return message;
    }
  }
}

class SlackFile extends Command {
  Function? get error => null;

  @override
  Future execute(DataCommand command) async {
    var data = DataSlackFile.fromJson(getParam(command));
    var slackFile = slack_data.SlackFile();
    slackFile.title = data.title;
    slackFile.initial_comment = data.initialComment;
    slackFile.file = File(data.filePath);
    slackFile.fileName = data.fileName;
    slackFile.mimeType = data.mimeType;

    var sender = SlackSender(data.token);
    await sender.sendFile(data.channel, slackFile);
    
    return await complete(0, command);
  }
}

class SlackBuild extends Command {
  @override
  Future execute(DataCommand command) async {
    var data = DataSlackBuild.fromJson(getParam(command));
    var channel = data.channel ?? 'build';
    await SlackSender(data.token).sendBuild(data.appName, data.type, Color.hex(data.color), data.version, data.downloadURL, channel: channel);

    return complete(0, command);
  }
}

void registerSlackCommands() {
  Command.register(
    CommandType.Slack,
    () => Slack(),
    spec: const CommandSpec(
      type: CommandType.Slack,
      category: 'notification',
      dataModel: 'DataSlackSender',
      samplePath: 'assets/yaml/sample/08_notification.yaml',
    ),
  );
  Command.register(
    CommandType.SlackFile,
    () => SlackFile(),
    spec: const CommandSpec(
      type: CommandType.SlackFile,
      category: 'notification',
      dataModel: 'DataSlackFile',
      samplePath: 'assets/yaml/sample/23_slack_file.yaml',
    ),
  );
  Command.register(
    CommandType.SlackBuild,
    () => SlackBuild(),
    spec: const CommandSpec(
      type: CommandType.SlackBuild,
      category: 'notification',
      dataModel: 'DataSlackBuild',
      samplePath: 'assets/yaml/sample/08_notification.yaml',
    ),
  );
}
