import 'dart:io';
import 'dart:math' as math;
import 'dart:typed_data';
import 'dart:ui';

import 'package:image/image.dart' as img;

import 'coin_detector.dart';

class CropResult {
  const CropResult({
    required this.bytes,
    required this.width,
    required this.height,
    required this.usedDetection,
  });

  final Uint8List bytes;
  final int width;
  final int height;
  final bool usedDetection;
}

/// Circular crop of the detected coin (square output with transparent-ish bg).
class CoinCropper {
  static Future<CropResult> cropAndCorrect({
    required String imagePath,
    CoinBox? box,
    double padding = 0.12,
  }) async {
    final raw = await File(imagePath).readAsBytes();
    var decoded = img.decodeImage(raw);
    if (decoded == null) {
      throw StateError('Failed to decode image: $imagePath');
    }
    decoded = img.bakeOrientation(decoded);

    final usedDetection = box != null;
    final center = box?.effectiveCenter ??
        Offset(decoded.width / 2, decoded.height / 2);
    var radius = box?.effectiveRadius ??
        math.min(decoded.width, decoded.height) * 0.35;
    radius *= (1 + padding);

    final size = (radius * 2).round().clamp(32, 2048);
    final out = img.Image(width: size, height: size, numChannels: 4);
    img.fill(out, color: img.ColorRgba8(0, 0, 0, 0));

    final r2 = radius * radius;
    for (var y = 0; y < size; y++) {
      for (var x = 0; x < size; x++) {
        final dx = x + 0.5 - size / 2;
        final dy = y + 0.5 - size / 2;
        if (dx * dx + dy * dy > r2) continue;
        final sx = (center.dx + dx).round();
        final sy = (center.dy + dy).round();
        if (sx < 0 || sy < 0 || sx >= decoded.width || sy >= decoded.height) {
          continue;
        }
        final p = decoded.getPixel(sx, sy);
        out.setPixelRgba(x, y, p.r.toInt(), p.g.toInt(), p.b.toInt(), 255);
      }
    }

    const outSize = 320;
    final resized = img.copyResize(
      out,
      width: outSize,
      height: outSize,
      interpolation: img.Interpolation.cubic,
    );
    final bytes = Uint8List.fromList(img.encodePng(resized));
    return CropResult(
      bytes: bytes,
      width: resized.width,
      height: resized.height,
      usedDetection: usedDetection,
    );
  }
}
