// ignore_for_file: unnecessary_question_mark

import 'dart:convert';

import 'package:collection/collection.dart';
import 'package:flux_ui/flux_ui.dart';
import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';

import '../../common/config.dart';
import '../../common/constants.dart';
import '../../common/tools.dart';
import '../../services/index.dart';
import '../serializers/blog.dart';

class Blog {
  final dynamic id;
  final String title;
  final String subTitle;
  final String date;
  final String content;
  final String author;
  final String imageFeature;
  final dynamic categoryId;
  final String excerpt;
  final String slug;
  final String authorImage;
  final List<String> audioUrls;
  final String videoUrl;
  final String link;
  final int commentCount;

  const Blog({
    this.id,
    this.title = '',
    this.subTitle = '',
    this.date = '',
    this.content = '',
    this.author = '',
    this.imageFeature = '',
    this.categoryId,
    this.excerpt = '',
    this.slug = '',
    this.authorImage = '',
    this.audioUrls = const <String>[],
    this.videoUrl = '',
    this.link = '',
    this.commentCount = 0,
  });

  const Blog.empty([this.id])
    : title = '',
      subTitle = '',
      date = '',
      author = '',
      content = '',
      imageFeature = '',
      categoryId = 0,
      excerpt = '',
      slug = '',
      audioUrls = const <String>[],
      videoUrl = '',
      authorImage = '',
      link = '',
      commentCount = 0;

  factory Blog.fromJson(Map<String, dynamic>? json) {
    if (json == null || json.isEmpty) {
      return const Blog.empty();
    }

    /// That means override blog from WordPress
    if ((ServerConfig().blog?.isNotEmpty ?? false) &&
        (ServerConfig().blog != ServerConfig().url)) {
      return Blog.fromWordpressJson(json);
    }

    switch (ServerConfig().type) {
      case ConfigType.shopify:
        return Blog.fromShopifyJson(json);
      case ConfigType.strapi:
        return Blog.fromStrapiJson(json);
      case ConfigType.notion:
        return Blog.fromNotionJson(json);
      case ConfigType.bigCommerce:
        return Blog.fromBigCommerceJson(json);
      case ConfigType.woo:
      case ConfigType.opencart:
      case ConfigType.magento:
      case ConfigType.dokan:
      case ConfigType.presta:
      case ConfigType.wcfm:
      case ConfigType.wordpress:
      case ConfigType.mylisting:
      case ConfigType.listeo:
      case ConfigType.listpro:
      default:
        return Blog.fromWordpressJson(json);
    }
  }

  factory Blog.fromShopifyJson(Map json) {
    final id = json['id'];
    final author = json['authorV2']?['name']?.toString() ?? '';
    final title = json['title']?.toString().unescape() ?? '';
    final content = json['contentHtml']?.toString() ?? '';
    final imageFeature = json['image']?['url']?.toString() ?? '';
    final date = DateFormat.yMMMMd().add_Hm().format(
      DateTime.parse(json['publishedAt']).toLocal(),
    );
    const categoryId = 0;
    const excerpt = '';
    const slug = '';
    const subTitle = '';
    const audioUrls = <String>[];
    const videoUrl = '';
    const authorImage = '';
    final link = json['onlineStoreUrl']?.toString() ?? '';
    const commentCount = 0;

    return Blog(
      id: id,
      author: author,
      title: title,
      subTitle: subTitle,
      content: content,
      imageFeature: imageFeature,
      date: date,
      categoryId: categoryId,
      excerpt: excerpt,
      slug: slug,
      audioUrls: audioUrls,
      videoUrl: videoUrl,
      authorImage: authorImage,
      link: link,
      commentCount: commentCount,
    );
  }

  factory Blog.fromStrapiJson(Map<String, dynamic> json) {
    var model = SerializerBlog.fromJson(json);
    final id = model.id;
    final author = model.user?.displayName ?? '';
    final title = model.title ?? '';
    final subTitle = model.subTitle ?? '';
    final content = model.content ?? '';
    final imageFeature = ServerConfig().url + model.images!.first.url!;
    final date = model.date ?? '';
    return Blog(
      author: author,
      title: title,
      subTitle: subTitle,
      content: content,
      id: id,
      date: date,
      imageFeature: imageFeature,
    );
  }

  factory Blog.fromWordpressJson(Map json) {
    String? imageFeature;

    var imgMedia = json['_embedded']?['wp:featuredmedia'];
    if (imgMedia is List && imgMedia.isNotEmpty) {
      imageFeature =
          imgMedia[0]?['media_details']?['sizes']?['large']?['source_url'];
      imageFeature ??= imgMedia[0]?['source_url'];
    } else {
      imageFeature ??= (json['image'] ?? json['image_feature']);
    }

    final author =
        json['_embedded']?['author']?[0]?['name'] ?? json['author_name'];
    final date = Tools.formatDate(json['date']);
    final id = json['id'];
    final title = json['title']?['rendered']?.toString().unescape();
    final subTitle = json['excerpt']?['rendered']?.toString().unescape();
    final content = json['content']?['rendered'];
    final categories = List.from(json['categories'] ?? []);
    final categoryId = categories.isNotEmpty ? categories.first : null;
    final excerpt = json['excerpt']?['rendered']?.toString().unescape();
    final slug = json['slug'];
    final authorImage =
        json['_embedded']?['author']?[0]?['avatar_urls']?['48'] ??
        json['post_author_avatar_urls']?['48'];
    final link = json['link'];
    final videoUrl = Videos.getVideoLink(content);

    var commentCount = 0;
    final replies = json['_embedded']?['replies'];

    if (replies != null && replies is List && replies.isNotEmpty) {
      final firstItem = replies.first;
      if (firstItem is Map) {
        commentCount = replies.length;
      } else if (firstItem is List) {
        commentCount = firstItem.length;
      }
    } else if (json['post_comment_count'] != null &&
        json['post_comment_count'] is int) {
      commentCount = json['post_comment_count'];
    }

    return Blog(
      author: author ?? '',
      title: title ?? '',
      subTitle: subTitle ?? '',
      content: content,
      id: id,
      date: date,
      imageFeature: imageFeature ?? '',
      categoryId: categoryId,
      excerpt: excerpt ?? '',
      slug: slug,
      authorImage: authorImage ?? '',
      audioUrls: _parseAudioLink(content),
      videoUrl: videoUrl ?? '',
      link: link,
      commentCount: commentCount,
    );
  }

  factory Blog.fromNotionJson(Map json) {
    var img = NotionDataTools.fromFile(json['properties']?['Image']);

    try {
      var id = json['id'];
      var title = NotionDataTools.fromTitle(
        json['properties']?['Name'],
      ).unescape();
      var subTitle = json['subTitle'] ?? '';
      var date = Tools.formatDate(
        json['properties']?['Created']?['created_time'],
      );
      var content = json['content'] ?? '';
      var author = json['properties']?['Author']?['created_by']?['name'];
      var authorImage =
          json['properties']?['Author']?['created_by']?['avatar_url'];

      var imageFeature = (img?.isNotEmpty ?? false) ? img!.first : '';
      var categoryId = 0;
      var excerpt = '';
      var slug = '';

      var audioUrls = const <String>[];
      var videoUrl = '';
      var link = json['url'];

      return Blog(
        author: author ?? '',
        title: title ?? '',
        subTitle: subTitle,
        content: content,
        id: id,
        date: date,
        imageFeature: imageFeature,
        categoryId: categoryId,
        excerpt: excerpt,
        slug: slug,
        authorImage: authorImage ?? '',
        audioUrls: audioUrls,
        videoUrl: videoUrl,
        link: link,
      );
    } catch (e, trace) {
      printLog(e);
      printLog(trace);
      rethrow;
    }
  }

  factory Blog.fromBigCommerceJson(Map json) {
    try {
      var id = json['id'];
      var title = json['title']?.toString().unescape() ?? '';
      var subTitle = json['subTitle'] ?? '';
      var date = Tools.formatDateToLocal(json['published_date']?['date']);
      var content = json['body'] ?? '';
      var author = json['author'];

      var imageFeature = json['thumbnail_path'] ?? '';
      var categoryId = 0;
      var excerpt = '';
      var slug = '';

      var audioUrls = const <String>[];
      var videoUrl = '';
      var link = json['url'];

      return Blog(
        author: author ?? '',
        title: title,
        subTitle: subTitle,
        content: content,
        id: id,
        date: date,
        imageFeature: imageFeature,
        categoryId: categoryId,
        excerpt: excerpt,
        slug: slug,
        audioUrls: audioUrls,
        videoUrl: videoUrl,
        link: link,
      );
    } catch (e, trace) {
      printLog(e);
      printLog(trace);
      rethrow;
    }
  }

  static Future getBlogs({
    String? url,
    categories,
    page = 1,
    String? lang,
  }) async {
    try {
      var param =
          '_embed&page=$page${kAdvanceConfig.alwaysRefreshBlog ? '&dummy=${DateTime.now().millisecondsSinceEpoch}' : ''}';
      if (categories != null) {
        param += '&categories=$categories';
      }
      if (lang != null) {
        param += '&lang=$lang';
      }
      final response = await http.get(
        '$url/wp-json/wp/v2/posts?$param'.toUri()!,
      );

      if (response.statusCode != 200) {
        return [];
      }
      return jsonDecode(response.body);
    } on Exception catch (_) {
      return [];
    }
  }

  bool get isAudioDetected => audioUrls.isNotEmpty;

  bool get isEmpty {
    return date == '' &&
        title == '' &&
        content == '' &&
        excerpt == '' &&
        imageFeature == '';
  }

  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'title': title,
      'subTitle': subTitle,
      'date': date,
      'content': content,
      'author': author,
      'imageFeature': imageFeature,
      'categoryId': categoryId ?? 0,
      'excerpt': excerpt,
      'slug': slug,
      'authorImage': authorImage,
      'audioUrls': audioUrls,
      'videoUrl': videoUrl,
      'link': link,
    };
  }

  factory Blog.fromLocalJson(Map json) {
    try {
      var id = json['id'];
      var title = json['title'];
      var subTitle = json['subTitle'];
      var date = json['date'];
      var content = json['content'];
      var author = json['author'];
      var imageFeature = json['imageFeature'];
      var categoryId = json['categoryId'] ?? 0;
      var excerpt = json['excerpt'];
      var slug = json['slug'];
      var authorImage = json['authorImage'];
      var audioUrls = List<String>.from(json['audioUrls'] ?? const <String>[]);
      var videoUrl = json['videoUrls'];
      var link = json['link'];

      return Blog(
        author: author,
        title: title,
        subTitle: subTitle,
        content: content,
        id: id,
        date: date,
        imageFeature: imageFeature ?? '',
        categoryId: categoryId,
        excerpt: excerpt,
        slug: slug,
        authorImage: authorImage ?? '',
        audioUrls: audioUrls,
        videoUrl: videoUrl ?? '',
        link: link,
      );
    } catch (e, trace) {
      printLog(e);
      printLog(trace);
      rethrow;
    }
  }

  Blog copyWith({
    dynamic? id,
    dynamic? categoryId,
    String? title,
    String? subTitle,
    String? date,
    String? content,
    String? author,
    String? imageFeature,
    String? excerpt,
    String? slug,
    String? authorImage,
    List<String>? audioUrls,
    String? videoUrl,
    String? link,
    int? commentCount,
  }) {
    return Blog(
      id: id ?? this.id,
      title: title ?? this.title,
      subTitle: subTitle ?? this.subTitle,
      date: date ?? this.date,
      content: content ?? this.content,
      author: author ?? this.author,
      imageFeature: imageFeature ?? this.imageFeature,
      categoryId: categoryId ?? this.categoryId,
      excerpt: excerpt ?? this.excerpt,
      slug: slug ?? this.slug,
      authorImage: authorImage ?? this.authorImage,
      audioUrls: audioUrls ?? this.audioUrls,
      videoUrl: videoUrl ?? this.videoUrl,
      link: link ?? this.link,
      commentCount: commentCount ?? this.commentCount,
    );
  }

  @override
  String toString() => 'Blog { id: $id  title: $title}';

  static List<String> _parseAudioLink(String content) {
    /// Detect .mp3 URLs in post content.
    final regExp = RegExp(
      r'(https?|ftp|file)://(www.)?(.*?)\.(mp3|m4a)',
      multiLine: true,
      caseSensitive: false,
    );
    var matches = regExp.allMatches(content);

    /// Get audio URLs from RegExp matches
    final matchesGroup = matches.map((item) => item.group(0) ?? '').toList();

    /// Remove redundant URLs
    final audioList = matchesGroup.toSet().toList()..remove('');
    return audioList;
  }

  static List<Blog> parseBlogList(List response, [Map? config]) {
    final list = <Blog>[];

    final blogs = <Blog>[];
    for (var item in response) {
      blogs.add(Blog.fromJson(item));
    }

    /// sort include blog
    final include = config?['include'];
    final sortId = <String>[];
    if (include != null) {
      if (include is List && include.isNotEmpty) {
        sortId.addAll(include.map((e) => e.toString()).toList());
      } else if (include is String && include.isNotEmpty) {
        sortId.addAll(include.split(','));
      }
    }

    if (sortId.isNotEmpty) {
      for (var id in sortId) {
        final blog = blogs.firstWhereOrNull(
          (element) => element.id.toString() == id,
        );
        if (blog != null) {
          list.add(blog);
        }
      }
    } else {
      list.addAll(blogs);
    }

    return list;
  }
}
