import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';

import '../../../../services/tilt_service.dart';

/// Rúd-libella buborék — kis kör alakú widget a kitűzőpanel fejlécébe.
///
/// Színküszöbök a DŐLÉSBŐL SZÁMOLT VÍZSZINTES HIBA szerint (a rúdmagasság
/// figyelembevételével), mert terepen ez a beszédes érték:
///   zöld < 1,5 cm · sárga < 3,5 cm · piros felette.
/// Mozgás közben és kalibrálatlanul szürke/kérdőjeles.
/// Koppintásra részletes nézet: nagy buborék, számok, rúdmagasság,
/// vezetett (1 vagy 2 lépéses) kalibráció.
class TiltBubble extends StatelessWidget {
  const TiltBubble({super.key, this.size = 34});

  final double size;

  @override
  Widget build(BuildContext context) {
    if (!Get.isRegistered<TiltService>()) return const SizedBox.shrink();

    return Obx(() {
      final t = TiltService.to;
      final inactive = !t.isCalibrated.value || t.isMoving.value;

      final errCm = t.horizontalErrorCm;
      final color = inactive
          ? Colors.grey
          : errCm < 1.5
              ? Colors.green
              : errCm < 3.5
                  ? Colors.orange
                  : Colors.red;

      return Tooltip(
        message: !t.isCalibrated.value
            ? 'Libella: nincs kalibrálva — koppints!'
            : t.isMoving.value
                ? 'Libella: mozgásban'
                : 'Dőlés ${t.tiltDeg.value.toStringAsFixed(1)}° '
                    '≈ ${errCm.toStringAsFixed(1)} cm',
        child: InkWell(
          onTap: () => _showDetail(context),
          customBorder: const CircleBorder(),
          child: SizedBox(
            width: size,
            height: size,
            child: _BubbleFace(
              size: size,
              color: color,
              inactive: inactive,
              uncalibrated: !t.isCalibrated.value,
              // A buborék a "lejtés" irányába csúszik — skála: 1 fok
              // dőlés ≈ a sugár ~25%-a, telítésig.
              dx: t.bubbleX.value,
              dy: t.bubbleY.value,
            ),
          ),
        ),
      );
    });
  }

  // ═════════════════════════════════════════════════════════════════
  // Részletes nézet + kalibráció
  // ═════════════════════════════════════════════════════════════════

  Future<void> _showDetail(BuildContext context) async {
    final t = TiltService.to;
    final poleCtrl =
        TextEditingController(text: t.poleHeight.value.toStringAsFixed(2));

    await Get.dialog(AlertDialog(
      title: const Text('Rúd-libella'),
      content: SingleChildScrollView(
        child: Obx(() {
          final errCm = t.horizontalErrorCm;
          final inactive = !t.isCalibrated.value || t.isMoving.value;
          final color = inactive
              ? Colors.grey
              : errCm < 1.5
                  ? Colors.green
                  : errCm < 3.5
                      ? Colors.orange
                      : Colors.red;

          return Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              SizedBox(
                width: 140,
                height: 140,
                child: _BubbleFace(
                  size: 140,
                  color: color,
                  inactive: inactive,
                  uncalibrated: !t.isCalibrated.value,
                  dx: t.bubbleX.value,
                  dy: t.bubbleY.value,
                ),
              ),
              const SizedBox(height: 10),
              Text(
                !t.isCalibrated.value
                    ? 'Nincs kalibrálva'
                    : t.isMoving.value
                        ? 'Mozgásban — állj meg a leolvasáshoz'
                        : '${t.tiltDeg.value.toStringAsFixed(2)}°  ≈  '
                            '${errCm.toStringAsFixed(1)} cm vízszintes hiba',
                style: TextStyle(
                    fontWeight: FontWeight.w700,
                    color: inactive ? Colors.grey : color),
              ),
              Text(
                '@ ${t.poleHeight.value.toStringAsFixed(2)} m rúdmagasság',
                style: TextStyle(fontSize: 11, color: Colors.grey.shade600),
              ),
              const SizedBox(height: 12),
              TextField(
                controller: poleCtrl,
                keyboardType:
                    const TextInputType.numberWithOptions(decimal: true),
                decoration: const InputDecoration(
                  labelText: 'Rúdmagasság (m)',
                  isDense: true,
                ),
                onSubmitted: (v) {
                  final m = double.tryParse(v.replaceAll(',', '.'));
                  if (m != null) t.setPoleHeight(m);
                },
              ),
              const SizedBox(height: 8),
              Text(
                'A jelzés csak akkor érvényes, ha a telefon MEREVEN, '
                'tartóban van a rúdon. Tartó-áthelyezés után kalibrálj újra.',
                style: TextStyle(fontSize: 11, color: Colors.grey.shade600),
              ),
            ],
          );
        }),
      ),
      actions: [
        if (TiltService.to.isCalibrated.value)
          TextButton(
            onPressed: () => TiltService.to.clearCalibration(),
            child: const Text('Kalibráció törlése'),
          ),
        TextButton(onPressed: Get.back, child: const Text('Bezár')),
        FilledButton.icon(
          icon: const Icon(Icons.architecture, size: 18),
          label: const Text('Kalibrálás'),
          onPressed: () async {
            final m = double.tryParse(poleCtrl.text.replaceAll(',', '.'));
            if (m != null) await TiltService.to.setPoleHeight(m);
            Get.back();
            await _calibrationFlow();
          },
        ),
      ],
    ));
  }

  /// Vezetett kalibráció: 1. lépés kötelező, 2. (180°-os átforgatásos)
  /// opcionális — utóbbi a tartó ferdeségét is kiejti.
  Future<void> _calibrationFlow() async {
    final t = TiltService.to;

    final step1Ok = await _captureStep(
      title: 'Kalibráció — 1/2',
      text: 'Állítsd a rudat FÜGGŐLEGESRE a szelencés libella szerint, '
          'és tartsd mozdulatlanul. A mérés 2 másodpercig tart.',
    );
    if (step1Ok != true) return;
    final v1 = await t.captureVector();
    HapticFeedback.mediumImpact();

    final doStep2 = await Get.dialog<bool>(AlertDialog(
      title: const Text('Kalibráció — pontosítás?'),
      content: const Text(
          'A pontosabb (tartó-ferdeséget is kiejtő) kalibrációhoz forgasd '
          'át a telefont a RÚD TENGELYE körül 180°-kal (a rúd maradjon '
          'függőleges), majd folytasd. Ki is hagyhatod — akkor az 1. '
          'lépés lesz a referencia.'),
      actions: [
        TextButton(
            onPressed: () => Get.back(result: false),
            child: const Text('Kihagyom')),
        FilledButton(
            onPressed: () => Get.back(result: true),
            child: const Text('Átforgattam — folytatás')),
      ],
    ));

    if (doStep2 == true) {
      final v2 = await t.captureVector();
      HapticFeedback.mediumImpact();
      await t.saveReference(v1, v2);
    } else {
      await t.saveReference(v1);
    }

    Get.snackbar('Libella', 'Kalibráció kész — a buborék él.',
        snackPosition: SnackPosition.BOTTOM,
        backgroundColor: const Color(0xFF2E7D32),
        colorText: const Color(0xFFFFFFFF));
  }

  Future<bool?> _captureStep({required String title, required String text}) {
    return Get.dialog<bool>(AlertDialog(
      title: Text(title),
      content: Text(text),
      actions: [
        TextButton(
            onPressed: () => Get.back(result: false),
            child: const Text('Mégse')),
        FilledButton(
            onPressed: () => Get.back(result: true),
            child: const Text('Indítás')),
      ],
    ));
  }
}

// ═══════════════════════════════════════════════════════════════════

class _BubbleFace extends StatelessWidget {
  final double size;
  final Color color;
  final bool inactive;
  final bool uncalibrated;
  final double dx;
  final double dy;

  const _BubbleFace({
    required this.size,
    required this.color,
    required this.inactive,
    required this.uncalibrated,
    required this.dx,
    required this.dy,
  });

  @override
  Widget build(BuildContext context) {
    // Skála: sin(4°) dőlésnél ér a széléhez.
    final r = size / 2;
    final scale = (r - size * 0.14) / 0.07;
    var ox = dx * scale;
    var oy = -dy * scale; // képernyő-y lefelé nő
    final d = (ox * ox + oy * oy);
    final maxR = r - size * 0.14;
    if (d > maxR * maxR) {
      final f = maxR / math.sqrt(d);
      ox *= f;
      oy *= f;
    }

    return CustomPaint(
      painter: _BubblePainter(
        color: color,
        inactive: inactive,
        ox: ox,
        oy: oy,
        dotRadius: size * 0.13,
      ),
      child: uncalibrated
          ? Center(
              child: Text('?',
                  style: TextStyle(
                      fontSize: size * 0.45,
                      fontWeight: FontWeight.w700,
                      color: Colors.grey)))
          : null,
    );
  }
}

class _BubblePainter extends CustomPainter {
  final Color color;
  final bool inactive;
  final double ox;
  final double oy;
  final double dotRadius;

  _BubblePainter({
    required this.color,
    required this.inactive,
    required this.ox,
    required this.oy,
    required this.dotRadius,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final c = Offset(size.width / 2, size.height / 2);
    final r = size.width / 2;

    canvas.drawCircle(
        c,
        r - 1,
        Paint()
          ..color = color.withOpacity(inactive ? 0.06 : 0.12)
          ..style = PaintingStyle.fill);
    canvas.drawCircle(
        c,
        r - 1,
        Paint()
          ..color = color.withOpacity(inactive ? 0.5 : 0.9)
          ..strokeWidth = 1.6
          ..style = PaintingStyle.stroke);
    // Belső célkör
    canvas.drawCircle(
        c,
        r * 0.35,
        Paint()
          ..color = color.withOpacity(0.5)
          ..strokeWidth = 1
          ..style = PaintingStyle.stroke);

    if (!inactive) {
      canvas.drawCircle(c + Offset(ox, oy), dotRadius, Paint()..color = color);
    }
  }

  @override
  bool shouldRepaint(_BubblePainter old) =>
      old.ox != ox ||
      old.oy != oy ||
      old.color != color ||
      old.inactive != inactive;
}
