// ignore_for_file: non_constant_identifier_names, avoid_init_to_null, constant_identifier_names
// ignore: depend_on_referenced_packages, implementation_imports

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

import 'package:json_annotation/json_annotation.dart';
import 'package:http/http.dart';
import 'package:http_parser/src/media_type.dart';
part 'slack_data.g.dart';

enum SlackBlockType { header, section, divider, actions }

enum SlackTextType { mrkdwn, plain_text }

enum SlackActionType { button, select, image }

enum SlackActionStyle { danger, primary }

@JsonSerializable()
class DataSlack {
  String channel;
  String? text;
  late List<SlackBlock>? blocks = null;
  late List<SlackAttachment>? attachments = null;
  bool? link_names;

  String get json
  {
    return jsonEncode(toJson());
  }

  DataSlack(this.channel);

  factory DataSlack.fromJson(Map<String, dynamic> json) =>
      _$DataSlackFromJson(json);
  Map<String, dynamic> toJson() {
    return removeKeys(_$DataSlackToJson(this));
  } 
}

Map<String, dynamic> removeKeys(Map<String, dynamic> map)
{
  var emptyKeys = [];
  for(var item in map.entries) {
    if(item.value == null) {
      emptyKeys.add(item.key);
    }
    if(item.value is List) {
      var list = item.value as List;
      if(list.isEmpty) {
        emptyKeys.add(item.key);
      }
    }
  }

  for(var key in emptyKeys) {
    map.remove(key);
  }
  return map;
}

@JsonSerializable()
class SlackBlock {
  late SlackBlockType type;
  late String? block_id = null;

  SlackBlock();

  factory SlackBlock.fromJson(Map<String, dynamic> json) =>
      _$SlackBlockFromJson(json);
  Map<String, dynamic> toJson() => removeKeys(_$SlackBlockToJson(this));
}

@JsonSerializable()
class SlackBlockHeader extends SlackBlock {
  late SlackBlockText? text;

  SlackBlockHeader() {
    super.type = SlackBlockType.header;
  }

  factory SlackBlockHeader.fromJson(Map<String, dynamic> json) =>
      _$SlackBlockHeaderFromJson(json);
  @override
  Map<String, dynamic> toJson() => removeKeys(_$SlackBlockHeaderToJson(this));
}

@JsonSerializable()
class SlackBlockSection extends SlackBlock {
  late SlackBlockText? text = null;
  late List<SlackBlockText>? fields = null;
  late SlackAccessory? accessory = null;

  SlackBlockSection()
  {
    type = SlackBlockType.section;
  }

  factory SlackBlockSection.fromJson(Map<String, dynamic> json) =>
      _$SlackBlockSectionFromJson(json);
  @override
  Map<String, dynamic> toJson() => removeKeys(_$SlackBlockSectionToJson(this));
}

@JsonSerializable()
class SlackAccessory {
  late SlackActionType type;
  late SlackBlockText? text = null;
  late String? image_url = null;
  late String? alt_text = null;
  late String? value = null;
  late String? url = null;

  SlackAccessory();

  factory SlackAccessory.fromJson(Map<String, dynamic> json) =>
      _$SlackAccessoryFromJson(json);
  Map<String, dynamic> toJson() => removeKeys(_$SlackAccessoryToJson(this));
}

@JsonSerializable()
class SlackBlockText {
  SlackTextType type = SlackTextType.mrkdwn;
  late String? text = null;
  late bool? emoji = null;

  SlackBlockText();

  factory SlackBlockText.fromJson(Map<String, dynamic> json) =>
      _$SlackBlockTextFromJson(json);
  Map<String, dynamic> toJson() => removeKeys(_$SlackBlockTextToJson(this));
}

@JsonSerializable()
class SlackAttachment {
  String? fallback;
  String? color;
  String? author_name;
  String? author_link;
  String? author_icon;
  String? title;
  String? title_link;
  String? pretext;
  String? text;
  String? image_url;
  String? thumb_url;
  String? footer;
  String? footer_icon;
  String? ts;

  late List<SlackBlock>? blocks = null;
  late List<SlackField>? fields = null;
  late List<SlackAction>? actions = null;

  SlackAttachment();

  factory SlackAttachment.fromJson(Map<String, dynamic> json) =>
      _$SlackAttachmentFromJson(json);
  Map<String, dynamic> toJson() => removeKeys(_$SlackAttachmentToJson(this));
}

@JsonSerializable()
class SlackField {
  String? title;
  String? value;
  bool? short = false;

  SlackField();
  SlackField.withParam(this.title, this.value, {this.short});

  factory SlackField.fromJson(Map<String, dynamic> json) =>
      _$SlackFieldFromJson(json);
  Map<String, dynamic> toJson() => removeKeys(_$SlackFieldToJson(this));
}

@JsonSerializable()
class SlackAction {
  SlackActionType? type;
  String? name;
  String? text;
  String? url;
  String? value;
  SlackActionStyle? style;
  /*SlackField options;
	SlackConfirm confirm;*/

  SlackAction();
  SlackAction.withParam(
      this.name, this.text, this.url, this.value, this.type, this.style);

  factory SlackAction.fromJson(Map<String, dynamic> json) =>
      _$SlackActionFromJson(json);
  Map<String, dynamic> toJson() => removeKeys(_$SlackActionToJson(this));
}

@JsonSerializable()
class SlackConfirm {
  String? title;
  String? text;
  String? ok_text;
  String? dismiss_text;
}

class SlackFile {
  String? title;
  String? initial_comment;
  String? fileName;
  String? mimeType;
  late File file;

  Future<MultipartRequest> setFileData(MultipartRequest form) async {
    // var bytes = await readFileByte(filePath!);
    if (title != null) {
      form.fields['title'] = title!;
    }
    if (initial_comment != null) {
      form.fields['initial_comment'] = initial_comment!;
    }
    form.fields['filetype'] =
        "auto"; //참조 - https://api.slack.com/types/file#file_types
    if (fileName != null && mimeType != null) {
      form.files.add(await MultipartFile.fromPath('file', file.path,
          contentType: MediaType(HttpHeaders.contentTypeHeader, mimeType!)));
    }
    var c = Completer<MultipartRequest>();
    c.complete(form);
    return c.future;
  }
}
