import 'dart:math' as math;
import '../data/models/shot.dart';

class GroupingResult {
  final double centerX; // Center of the group (relative 0-1)
  final double centerY;
  final double diameter; // Maximum spread diameter (relative 0-1)
  final double standardDeviation; // Dispersion metric
  final double meanRadius; // Average distance from center
  final int shotCount;

  GroupingResult({
    required this.centerX,
    required this.centerY,
    required this.diameter,
    required this.standardDeviation,
    required this.meanRadius,
    required this.shotCount,
  });

  /// Grouping quality rating (1-5 stars)
  int get qualityRating {
    // Based on standard deviation relative to typical target size
    if (standardDeviation < 0.02) return 5;
    if (standardDeviation < 0.04) return 4;
    if (standardDeviation < 0.06) return 3;
    if (standardDeviation < 0.10) return 2;
    return 1;
  }

  String get qualityDescription {
    switch (qualityRating) {
      case 5:
        return 'Excellent';
      case 4:
        return 'Tres bien';
      case 3:
        return 'Bien';
      case 2:
        return 'Moyen';
      default:
        return 'A ameliorer';
    }
  }

  factory GroupingResult.empty() {
    return GroupingResult(
      centerX: 0.5,
      centerY: 0.5,
      diameter: 0,
      standardDeviation: 0,
      meanRadius: 0,
      shotCount: 0,
    );
  }
}

class GroupingAnalyzerService {
  /// Analyze the grouping of a list of shots
  GroupingResult analyzeGrouping(List<Shot> shots) {
    if (shots.isEmpty) {
      return GroupingResult.empty();
    }

    if (shots.length == 1) {
      return GroupingResult(
        centerX: shots.first.x,
        centerY: shots.first.y,
        diameter: 0,
        standardDeviation: 0,
        meanRadius: 0,
        shotCount: 1,
      );
    }

    // Calculate center of group (centroid)
    double sumX = 0;
    double sumY = 0;

    for (final shot in shots) {
      sumX += shot.x;
      sumY += shot.y;
    }

    final centerX = sumX / shots.length;
    final centerY = sumY / shots.length;

    // Calculate distances from center
    final distances = <double>[];
    for (final shot in shots) {
      final dx = shot.x - centerX;
      final dy = shot.y - centerY;
      distances.add(math.sqrt(dx * dx + dy * dy));
    }

    // Calculate mean radius
    final meanRadius = distances.reduce((a, b) => a + b) / distances.length;

    // Calculate standard deviation
    double sumSquaredDiff = 0;
    for (final distance in distances) {
      sumSquaredDiff += math.pow(distance - meanRadius, 2);
    }
    final standardDeviation = math.sqrt(sumSquaredDiff / distances.length);

    // Calculate maximum spread (diameter)
    // Find the two points that are farthest apart
    double maxDistance = 0;

    for (int i = 0; i < shots.length; i++) {
      for (int j = i + 1; j < shots.length; j++) {
        final dx = shots[i].x - shots[j].x;
        final dy = shots[i].y - shots[j].y;
        final distance = math.sqrt(dx * dx + dy * dy);
        if (distance > maxDistance) {
          maxDistance = distance;
        }
      }
    }

    return GroupingResult(
      centerX: centerX,
      centerY: centerY,
      diameter: maxDistance,
      standardDeviation: standardDeviation,
      meanRadius: meanRadius,
      shotCount: shots.length,
    );
  }

  /// Calculate offset from target center
  (double, double) calculateOffset({
    required double groupCenterX,
    required double groupCenterY,
    required double targetCenterX,
    required double targetCenterY,
  }) {
    return (
      groupCenterX - targetCenterX,
      groupCenterY - targetCenterY,
    );
  }

  /// Get directional offset description (e.g., "haut-gauche")
  String getOffsetDescription(double offsetX, double offsetY) {
    if (offsetX.abs() < 0.02 && offsetY.abs() < 0.02) {
      return 'Centre';
    }

    String vertical = '';
    String horizontal = '';

    if (offsetY < -0.02) {
      vertical = 'Haut';
    } else if (offsetY > 0.02) {
      vertical = 'Bas';
    }

    if (offsetX < -0.02) {
      horizontal = 'Gauche';
    } else if (offsetX > 0.02) {
      horizontal = 'Droite';
    }

    if (vertical.isNotEmpty && horizontal.isNotEmpty) {
      return '$vertical-$horizontal';
    }

    return vertical.isNotEmpty ? vertical : horizontal;
  }

  /// Analyze trend across multiple sessions
  GroupingTrend analyzeTrend(List<GroupingResult> results) {
    if (results.length < 2) {
      return GroupingTrend(
        improving: false,
        averageDiameter: results.isEmpty ? 0 : results.first.diameter,
        recentDiameter: results.isEmpty ? 0 : results.first.diameter,
        improvementPercentage: 0,
      );
    }

    // Calculate averages for first half vs second half
    final midpoint = results.length ~/ 2;
    final firstHalf = results.sublist(0, midpoint);
    final secondHalf = results.sublist(midpoint);

    double firstHalfAvg = 0;
    for (final r in firstHalf) {
      firstHalfAvg += r.diameter;
    }
    firstHalfAvg /= firstHalf.length;

    double secondHalfAvg = 0;
    for (final r in secondHalf) {
      secondHalfAvg += r.diameter;
    }
    secondHalfAvg /= secondHalf.length;

    // Overall average
    double totalAvg = 0;
    for (final r in results) {
      totalAvg += r.diameter;
    }
    totalAvg /= results.length;

    final improvement = ((firstHalfAvg - secondHalfAvg) / firstHalfAvg) * 100;

    return GroupingTrend(
      improving: secondHalfAvg < firstHalfAvg,
      averageDiameter: totalAvg,
      recentDiameter: secondHalfAvg,
      improvementPercentage: improvement,
    );
  }
}

class GroupingTrend {
  final bool improving;
  final double averageDiameter;
  final double recentDiameter;
  final double improvementPercentage;

  GroupingTrend({
    required this.improving,
    required this.averageDiameter,
    required this.recentDiameter,
    required this.improvementPercentage,
  });
}
