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

import 'package:flutter/services.dart';
import 'package:flutter_svg/svg.dart';
import 'package:mutex/mutex.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/locator.dart';
import 'package:twonly/src/utils/log.dart';

const defaultAvatarSvg = '''
<!-- Taken from: https://getavataaars.com/ -->
<svg width="264px" height="280px" viewBox="0 0 264 280" version="1.1" xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
        <path
            d="M124,144.610951 L124,163 L128,163 L128,163 C167.764502,163 200,195.235498 200,235 L200,244 L0,244 L0,235 C-4.86974701e-15,195.235498 32.235498,163 72,163 L72,163 L76,163 L76,144.610951 C58.7626345,136.422372 46.3722246,119.687011 44.3051388,99.8812385 C38.4803105,99.0577866 34,94.0521096 34,88 L34,74 C34,68.0540074 38.3245733,63.1180731 44,62.1659169 L44,56 L44,56 C44,25.072054 69.072054,5.68137151e-15 100,0 L100,0 L100,0 C130.927946,-5.68137151e-15 156,25.072054 156,56 L156,62.1659169 C161.675427,63.1180731 166,68.0540074 166,74 L166,88 C166,94.0521096 161.51969,99.0577866 155.694861,99.8812385 C153.627775,119.687011 141.237365,136.422372 124,144.610951 Z"
            id="react-path-3"></path>
    </defs>
    <g id="Avataaar" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <g transform="translate(-825.000000, -1100.000000)">
            <g transform="translate(825.000000, 1100.000000)">
                <g id="Avataaar" stroke-width="1" fill-rule="evenodd">
                    <g id="Body" transform="translate(32.000000, 36.000000)">
                        <mask id="react-mask-6" fill="white">
                            <use xlink:href="#react-path-3"></use>
                        </mask>
                        <g id="Skin/👶🏽-03-Brown" mask="url(#react-mask-6)" fill="#57CC99">
                            <g transform="translate(0.000000, 0.000000)" id="Color">
                                <rect x="0" y="0" width="264" height="280"></rect>
                            </g>
                        </g>
                    </g>
                </g>
            </g>
        </g>
    </g>
</svg>''';

String getAvatarSvg(Uint8List avatarSvgCompressed) {
  try {
    // Check for GZIP magic bytes (0x1F 0x8B)
    final isGzip =
        avatarSvgCompressed.length >= 2 &&
        avatarSvgCompressed[0] == 0x1F &&
        avatarSvgCompressed[1] == 0x8B;

    final decodedBytes = isGzip
        ? gzip.decode(avatarSvgCompressed)
        : avatarSvgCompressed;
    return utf8.decode(decodedBytes);
  } catch (e) {
    Log.error('Failed to decode avatar SVG: $e');
    return defaultAvatarSvg;
  }
}

Future<void> createPushAvatars({int? forceForUserId}) async {
  final contacts = await twonlyDB.contactsDao.getAllContacts();

  for (final contact in contacts) {
    try {
      if (contact.avatarSvgCompressed == null) continue;

      if (forceForUserId == null) {
        if (avatarPNGFile(contact.userId).existsSync()) {
          continue; // only create the avatar in case no avatar exists yet fot this user
        }
      } else if (contact.userId != forceForUserId) {
        // only update the avatar for this specified contact
        continue;
      }

      final avatarSvg = getAvatarSvg(contact.avatarSvgCompressed!);

      final pictureInfo = await vg.loadPicture(
        SvgStringLoader(avatarSvg),
        null,
      );

      final image = await pictureInfo.picture.toImage(270, 300);

      final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
      final pngBytes = byteData!.buffer.asUint8List();

      await avatarPNGFile(contact.userId).writeAsBytes(pngBytes);
      pictureInfo.picture.dispose();
    } catch (e) {
      Log.error(e);
    }
  }
}

File avatarPNGFile(int contactId) {
  final avatarsDirectory = Directory(
    '${AppEnvironment.cacheDir}/avatars',
  );

  if (!avatarsDirectory.existsSync()) {
    avatarsDirectory.createSync(recursive: true);
  }
  return File('${avatarsDirectory.path}/$contactId.png');
}

File currentUserAvatarFile(int avatarCounter) {
  final avatarsDirectory = Directory(
    '${AppEnvironment.cacheDir}/avatars',
  );

  if (!avatarsDirectory.existsSync()) {
    avatarsDirectory.createSync(recursive: true);
  }
  return File('${avatarsDirectory.path}/user_$avatarCounter.png');
}

final _avatarMutex = Mutex();

Future<String?> getUserAvatar() async {
  if (userService.currentUser.avatarSvg == null) {
    return null;
  }

  return _avatarMutex.protect(() async {
    final avatarCounter = userService.currentUser.avatarCounter;
    final file = currentUserAvatarFile(avatarCounter);
    if (file.existsSync()) {
      return file.path;
    }

    final pictureInfo = await vg.loadPicture(
      SvgStringLoader(userService.currentUser.avatarSvg!),
      null,
    );

    final image = await pictureInfo.picture.toImage(270, 300);

    final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
    final pngBytes = byteData!.buffer.asUint8List();

    await file.writeAsBytes(pngBytes, flush: true);
    pictureInfo.picture.dispose();

    return file.path;
  });
}
