import 'dart:convert';
import 'dart:typed_data';

import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flashlink/app/extensions/img_extension.dart';
import 'package:shimmer/shimmer.dart';
import 'dart:io';

import '../constants/configs.dart';

enum ImageSourceType { network, asset, file, memory }

class IXImage extends StatelessWidget {
  // 静态缓存，避免重复解码 base64 数据
  static final Map<String, Uint8List> _memoryImageCache = {};

  /// 清理内存图片缓存
  static void clearMemoryCache() {
    _memoryImageCache.clear();
  }

  /// 获取缓存大小
  static int get cacheSize => _memoryImageCache.length;

  const IXImage({
    super.key,
    required this.source,
    required this.width,
    required this.height,
    this.sourceType = ImageSourceType.network,
    this.fadeOutDuration,
    this.fadeInDuration,
    this.origAspectRatio,
    this.borderRadius,
    this.fit,
    this.placeholderDuration = const Duration(milliseconds: 400),
  });

  final String source;
  final ImageSourceType sourceType;
  final double width;
  final double height;
  final Duration? fadeOutDuration;
  final Duration? fadeInDuration;
  final double? origAspectRatio;
  final double? borderRadius;
  final BoxFit? fit;
  final Duration placeholderDuration;

  @override
  Widget build(BuildContext context) {
    int? memCacheWidth, memCacheHeight;
    double aspectRatio = (width / height).toDouble();

    void setMemCacheSizes() {
      if (aspectRatio > 1) {
        memCacheHeight = height.cacheSize(context);
      } else if (aspectRatio < 1) {
        memCacheWidth = width.cacheSize(context);
      } else {
        if (origAspectRatio != null && origAspectRatio! > 1) {
          memCacheWidth = width.cacheSize(context);
        } else if (origAspectRatio != null && origAspectRatio! < 1) {
          memCacheHeight = height.cacheSize(context);
        } else {
          memCacheWidth = width.cacheSize(context);
          memCacheHeight = height.cacheSize(context);
        }
      }
    }

    setMemCacheSizes();

    if (memCacheWidth == null && memCacheHeight == null) {
      memCacheWidth = width.toInt();
    }

    return ClipRRect(
      key: ValueKey('ix_image_${source.hashCode}_${width}_$height'),
      clipBehavior: Clip.antiAlias,
      borderRadius: BorderRadius.circular(borderRadius ?? 0),
      child: _buildImage(context, memCacheWidth, memCacheHeight),
    );
  }

  Widget _buildImage(
    BuildContext context,
    int? memCacheWidth,
    int? memCacheHeight,
  ) {
    switch (sourceType) {
      case ImageSourceType.network:
        String url = source;
        if (source.indexOf("http") != 0) {
          url = "${Configs.assetUrl}/$source";
        }
        return CachedNetworkImage(
          key: ValueKey(url),
          imageUrl: url,
          width: width,
          height: height,
          memCacheWidth: memCacheWidth,
          memCacheHeight: memCacheHeight,
          fit: fit ?? BoxFit.cover,
          fadeOutDuration: fadeOutDuration ?? const Duration(milliseconds: 250),
          fadeInDuration: fadeInDuration ?? const Duration(milliseconds: 350),
          filterQuality: FilterQuality.medium,
          errorWidget: (context, url, error) =>
              _buildErrorWidget(context, url, error),
          placeholder: (context, url) => _buildPlaceholder(context, url),
        );
      case ImageSourceType.asset:
        return Image.asset(
          source,
          width: width,
          height: height,
          fit: fit ?? BoxFit.cover,
          alignment: fit == BoxFit.fitWidth
              ? Alignment.topCenter
              : Alignment.center,
          errorBuilder: (context, error, stackTrace) =>
              _buildErrorWidget(context, source, error),
        );
      case ImageSourceType.file:
        return Image.file(
          File(source),
          width: width,
          height: height,
          fit: fit ?? BoxFit.cover,
          errorBuilder: (context, error, stackTrace) =>
              _buildErrorWidget(context, source, error),
        );
      case ImageSourceType.memory:
        // 使用缓存避免重复解码
        Uint8List imageBytes;
        if (_memoryImageCache.containsKey(source)) {
          imageBytes = _memoryImageCache[source]!;
        } else {
          imageBytes = base64Decode(source);
          _memoryImageCache[source] = imageBytes;
        }

        return Image.memory(
          imageBytes,
          key: ValueKey('memory_${source.hashCode}'),
          width: width,
          height: height,
          fit: fit ?? BoxFit.cover,
          errorBuilder: (context, error, stackTrace) =>
              _buildErrorWidget(context, source, error),
        );
    }
  }

  Widget _buildErrorWidget(BuildContext context, String url, dynamic error) {
    return _buildSmoothPlaceholder(context, isError: false);
  }

  Widget _buildPlaceholder(BuildContext context, String url) {
    return _buildSmoothPlaceholder(context, isError: false);
  }

  Widget _buildSmoothPlaceholder(
    BuildContext context, {
    required bool isError,
  }) {
    return AnimatedContainer(
      duration: placeholderDuration,
      curve: Curves.easeInOut,
      width: width,
      height: height,
      decoration: BoxDecoration(
        gradient: LinearGradient(
          begin: Alignment.topLeft,
          end: Alignment.bottomRight,
          colors: isError
              ? [
                  Colors.red.withValues(alpha: 0.15),
                  Colors.red.withValues(alpha: 0.08),
                  Colors.red.withValues(alpha: 0.15),
                ]
              : [
                  Colors.grey.withValues(alpha: 0.25),
                  Colors.grey.withValues(alpha: 0.08),
                  Colors.grey.withValues(alpha: 0.25),
                ],
          stops: const [0.0, 0.5, 1.0],
        ),
        borderRadius: BorderRadius.circular(borderRadius ?? 0),
      ),
      child: Shimmer.fromColors(
        baseColor: isError
            ? Colors.red.withValues(alpha: 0.3)
            : Colors.grey.withValues(alpha: 0.4),
        highlightColor: isError
            ? Colors.red.withValues(alpha: 0.1)
            : Colors.grey.withValues(alpha: 0.1),
        period: const Duration(milliseconds: 1800),
        child: Container(
          width: width,
          height: height,
          decoration: BoxDecoration(
            color: Colors.white.withValues(alpha: 0.15),
            borderRadius: BorderRadius.circular(borderRadius ?? 0),
          ),
        ),
      ),
    );
  }
}
