import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'dart:math' as math; // Serve per i calcoli della freccia

// --- PAINTER PER IL DISEGNO (A SCHERMO E SU PDF) ---
class PainterV40 extends CustomPainter {
  final List<TrattoPenna> tr;
  final List<ElementoGrafico> el;

  PainterV40(this.tr, this.el);

  @override
  void paint(Canvas canvas, Size size) {
    // Stile della penna (Strada/Linee)
    Paint pStrada = Paint()
      ..color = Colors.black
      ..strokeWidth = 3.0
      ..style = PaintingStyle.stroke
      ..strokeCap = StrokeCap.round;

    // 1. DISEGNO TRATTI (PENNA E FRECCE)
    for (var t in tr) {
      if (t.punti.length > 1) {
        Path path = Path()..moveTo(t.punti[0].dx, t.punti[0].dy);
        for (var pt in t.punti) path.lineTo(pt.dx, pt.dy);

        canvas.drawPath(path, pStrada);

        // Se è una freccia, disegna la punta alla fine
        if (t.tipo == 'freccia') {
          // Prendi gli ultimi due punti per calcolare l'angolazione
          _disegnaPunta(canvas, t.punti[t.punti.length - 2], t.punti.last, pStrada);
        }
      }
    }

    // 2. DISEGNO ELEMENTI (AUTO E TESTO)
    for (var e in el) {
      canvas.save();
      // Sposta e ruota il canvas nella posizione dell'elemento
      canvas.translate(e.posizione.dx, e.posizione.dy);
      canvas.rotate(e.rotazione);

      if (e.tipo == 'testo') {
        _disegnaTesto(canvas, e.label ?? "");
      } else {
        _disegnaAuto(canvas, e.tipo == 'autoA' ? 'A' : 'B', e.tipo == 'autoA' ? Colors.blue : Colors.orange);
      }
      canvas.restore();
    }
  }

  // Disegna il rettangolo dell'auto con la lettera
  void _disegnaAuto(Canvas canvas, String lettera, Color colore) {
    Paint p = Paint()..color = colore;
    // Auto centrata (70x40 px)
    Rect r = Rect.fromCenter(center: Offset.zero, width: 70, height: 40);
    canvas.drawRect(r, p);

    // Bordo nero auto
    canvas.drawRect(r, Paint()..color = Colors.black..style = PaintingStyle.stroke..strokeWidth = 2);

    // Lettera centrata
    final tp = TextPainter(
        text: TextSpan(text: lettera, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16)),
        textDirection: TextDirection.ltr
    )..layout();

    tp.paint(canvas, Offset(-tp.width / 2, -tp.height / 2));
  }

  // Disegna etichette di testo
  void _disegnaTesto(Canvas canvas, String txt) {
    final tp = TextPainter(
        text: TextSpan(text: txt, style: const TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.bold, backgroundColor: Colors.white70)),
        textDirection: TextDirection.ltr
    )..layout();
    tp.paint(canvas, Offset(-tp.width / 2, -tp.height / 2));
  }

  // Calcola e disegna la punta della freccia
  void _disegnaPunta(Canvas canvas, Offset p1, Offset p2, Paint paint) {
    double angle = (p2 - p1).direction;
    // Disegna due linee inclinate rispetto alla direzione finale
    canvas.drawLine(p2, p2 - Offset.fromDirection(angle - 0.5, 15), paint);
    canvas.drawLine(p2, p2 - Offset.fromDirection(angle + 0.5, 15), paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}

// --- MODELLO DATI: TRATTO PENNA ---
class TrattoPenna {
  List<Offset> punti;
  String tipo; // 'penna' o 'freccia'

  TrattoPenna(this.punti, {this.tipo = 'penna'});

  // Metodo utile per la cancellazione (hit test)
  bool contiene(Offset p) {
    for (var punto in punti) {
      if ((p - punto).distance < 20.0) return true;
    }
    return false;
  }

  Map<String, dynamic> toMap() => {
    'punti': punti.map((p) => {'dx': p.dx, 'dy': p.dy}).toList(),
    'tipo': tipo,
  };

  factory TrattoPenna.fromMap(Map<String, dynamic> map) => TrattoPenna(
    (map['punti'] as List).map((p) => Offset(p['dx'], p['dy'])).toList(),
    tipo: map['tipo'] ?? 'penna',
  );
}

// --- MODELLO DATI: ELEMENTO GRAFICO (AUTO/TESTO) ---
class ElementoGrafico {
  Offset posizione;
  String tipo; // 'autoA', 'autoB', 'testo'
  double rotazione;
  String? label;

  ElementoGrafico(this.posizione, this.tipo, {this.rotazione = 0, this.label});

  Map<String, dynamic> toMap() => {
    'pos': {'dx': posizione.dx, 'dy': posizione.dy},
    'tipo': tipo,
    'rot': rotazione,
    'label': label,
  };

  factory ElementoGrafico.fromMap(Map<String, dynamic> map) => ElementoGrafico(
    Offset(map['pos']['dx'], map['pos']['dy']),
    map['tipo'],
    rotazione: (map['rot'] as num?)?.toDouble() ?? 0,
    label: map['label'],
  );

  bool contiene(Offset p) => (p - posizione).distance < 35;

  // --- METODO CRUCIALE PER IL PDF ---
  // Genera un'immagine PNG ritagliata e ottimizzata del grafico
  static Future<Uint8List?> fondiGraficoDinamica(List<dynamic> trattiRaw, List<dynamic> elementiRaw) async {
    // Conversione sicura dei tipi (nel caso arrivino come dynamic da GlobalData)
    List<TrattoPenna> tratti = trattiRaw.cast<TrattoPenna>();
    List<ElementoGrafico> elementi = elementiRaw.cast<ElementoGrafico>();

    if (tratti.isEmpty && elementi.isEmpty) return null;

    // 1. Calcolo Bounding Box (i confini del disegno)
    double minX = double.infinity, minY = double.infinity;
    double maxX = double.negativeInfinity, maxY = double.negativeInfinity;

    void checkPoint(Offset p) {
      if (p.dx < minX) minX = p.dx;
      if (p.dx > maxX) maxX = p.dx;
      if (p.dy < minY) minY = p.dy;
      if (p.dy > maxY) maxY = p.dy;
    }

    for (var t in tratti) { for (var p in t.punti) checkPoint(p); }
    for (var e in elementi) checkPoint(e.posizione);

    // Se non ci sono dimensioni valide, esci
    if (minX == double.infinity) return null;

    // Aggiungiamo margine (padding) bianco intorno
    const double pad = 40.0;
    double width = (maxX - minX) + (pad * 2);
    double height = (maxY - minY) + (pad * 2);

    // 2. Disegno su Canvas off-screen
    final recorder = ui.PictureRecorder();
    // Crea canvas delle dimensioni esatte
    final canvas = ui.Canvas(recorder, Rect.fromLTWH(0, 0, width, height));

    // Sfondo Bianco (Copre la griglia del modulo sottostante)
    canvas.drawRect(Rect.fromLTWH(0, 0, width, height), Paint()..color = Colors.white);

    // Sposta l'origine del canvas per centrare il disegno ed eliminare lo spazio vuoto in alto/sinistra
    canvas.translate(-minX + pad, -minY + pad);

    // Usa il painter esistente per ridisegnare tutto
    final painter = PainterV40(tratti, elementi);
    painter.paint(canvas, Size(width, height));

    // 3. Conversione in PNG
    final picture = recorder.endRecording();
    final img = await picture.toImage(width.toInt(), height.toInt());
    final pngBytes = await img.toByteData(format: ui.ImageByteFormat.png);

    return pngBytes?.buffer.asUint8List();
  }
}