import 'dart:io';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:image/image.dart' as img;
import 'package:clashmi/app/runtime/return_result.dart';
import 'package:clashmi/app/utils/log.dart';
import 'package:zxing2/qrcode.dart';

class QrcodeUtils {
  static ReturnResult<Image> toImage(String content) {
    try {
      var hints = EncodeHints();
      hints.put<CharacterSetECI>(
          EncodeHintType.characterSet, CharacterSetECI.UTF8);
      hints.put<bool>(EncodeHintType.gs1Format, true);
      var qrcode =
          Encoder.encode(content, ErrorCorrectionLevel.h, hints: hints);
      var matrix = qrcode.matrix!;
      var scale = 4;
      var image = img.Image(
          width: matrix.width * scale,
          height: matrix.height * scale,
          numChannels: 4);
      for (var x = 0; x < matrix.width; x++) {
        for (var y = 0; y < matrix.height; y++) {
          if (matrix.get(x, y) == 1) {
            img.fillRect(image,
                x1: x * scale,
                y1: y * scale,
                x2: x * scale + scale,
                y2: y * scale + scale,
                color: img.ColorRgba8(0, 0, 0, 0xFF));
          }
        }
      }
      final png = img.encodePng(image);
      return ReturnResult(data: Image.memory(png));
    } catch (err) {
      return ReturnResult(error: ReturnResultError(err.toString()));
    }
  }

  static Future<bool> saveAsImage(String content, String path) async {
    try {
      var qrcode = Encoder.encode(content, ErrorCorrectionLevel.h);
      var matrix = qrcode.matrix!;
      var scale = 4;
      var image = img.Image(
          width: matrix.width * scale,
          height: matrix.height * scale,
          numChannels: 4);
      for (var x = 0; x < matrix.width; x++) {
        for (var y = 0; y < matrix.height; y++) {
          if (matrix.get(x, y) == 1) {
            img.fillRect(image,
                x1: x * scale,
                y1: y * scale,
                x2: x * scale + scale,
                y2: y * scale + scale,
                color: img.ColorRgba8(0, 0, 0, 0xFF));
          }
        }
      }
      final png = img.encodePng(image);
      await File(path).writeAsBytes(png);
    } catch (err) {
      Log.w("QrcodeUtils.saveAsImage exception ${err.toString()}");
      return false;
    }
    return true;
  }

  static Future<String?> scanFromFile(String filePath) async {
    var image = await img.decodeImageFile(filePath);
    if (image == null) {
      return null;
    }
    LuminanceSource source = RGBLuminanceSource(
        image.width,
        image.height,
        image
            .convert(numChannels: 4)
            .getBytes(order: img.ChannelOrder.abgr)
            .buffer
            .asInt32List());
    var bitmap = BinaryBitmap(GlobalHistogramBinarizer(source));
    var reader = QRCodeReader();
    var result = reader.decode(bitmap);

    return result.text;
  }

  static Future<String?> scanFromImageData(Uint8List data) async {
    var image = img.decodeImage(data);
    if (image == null) {
      return null;
    }
    LuminanceSource source = RGBLuminanceSource(
        image.width,
        image.height,
        image
            .convert(numChannels: 4)
            .getBytes(order: img.ChannelOrder.abgr)
            .buffer
            .asInt32List());
    var bitmap = BinaryBitmap(GlobalHistogramBinarizer(source));
    var reader = QRCodeReader();
    var result = reader.decode(bitmap);

    return result.text;
  }
}
